Consolidate old sample apps into new demo app.

This commit is contained in:
Kevin Gorham 2019-10-21 06:17:07 -04:00
parent bb824450b0
commit 190f7f5548
No known key found for this signature in database
GPG Key ID: CCA55602DF49FC38
144 changed files with 2217 additions and 1840 deletions

View File

@ -1 +0,0 @@
/build

View File

@ -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'
}

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cash.z.wallet.sdk.sample.address">
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -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<Any?, ByteArray>,
spendingKeyProvider: ReadWriteProperty<Any?, String>
): 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
}
}

View File

@ -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<String>()
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()
}
}

View File

@ -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()
}
}

View File

@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
<item
android:color="#00000000"
android:offset="1.0"/>
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
</vector>

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/text_address_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="60dp"
android:onClick="onTestThings"
android:text="Test Something"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>

View File

@ -1,3 +0,0 @@
<resources>
<string name="app_name">Zcash Address</string>
</resources>

View File

@ -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
}

View File

@ -1,3 +0,0 @@
include ':app', ":sdk"
project(":sdk").projectDir = file("../../../zcash-android-wallet-sdk")
rootProject.name='Zcash Address'

View File

@ -0,0 +1,67 @@
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'
}
}
}
dependencies {
// SDK
implementation project(path: ':sdk')
// implementation "cash.z.android.wallet:zcash-android-testnet:$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.0"
implementation "androidx.room:room-common:2.2.0"
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.0"
// 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.0.0'
implementation 'androidx.navigation:navigation-ui:2.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.0.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-beta01"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-beta01" // provides lifecycleScope!
}

View File

@ -0,0 +1,24 @@
package cash.z.wallet.sdk.sample.demoapp
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("cash.z.wallet.sdk.sample.demoapp", appContext.packageName)
}
}

View File

@ -0,0 +1,163 @@
package cash.z.wallet.sdk.sample.demoapp
import androidx.test.platform.app.InstrumentationRegistry
import cash.z.wallet.sdk.data.*
import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
import cash.z.wallet.sdk.ext.ZcashSdk
import cash.z.wallet.sdk.ext.convertZecToZatoshi
import cash.z.wallet.sdk.ext.toZec
import cash.z.wallet.sdk.secure.Wallet
import cash.z.wallet.sdk.service.LightWalletGrpcService
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
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 {
private val seed = "Insert seed for testing".toByteArray()
private val lightwalletdHost: String = "34.68.177.238"
// ///////////////////////////////////////////////////
// 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 wallet = Wallet()
val privateKeys = wallet.initialize(context, seed)
assertNotNull("Wallet already existed.", privateKeys)
log("Spending Key: ${privateKeys?.get(0)}")
log("Address: ${wallet.getAddress()}")
}
/////////////////////////////////////////////////////
// Derive address from Extended Spending Key
@Test fun getAddressFromSpendingKey() {
// TODO: turn spending key into viewing key via:
// let extfvks: Vec<_> = extsks.iter().map(ExtendedFullViewingKey::from).collect();
// val viewingKey = spendingKey //.asViewingKey()
// return getAddressFromViewingKey(viewingKey)
}
/////////////////////////////////////////////////////
// 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 wallet = Wallet()
val repository = PagedTransactionRepository(context)
val keyManager = SampleStorageBridge().securelyStoreSeed(seed)
val encoder = WalletTransactionEncoder(wallet, repository, keyManager)
val amount = 0.123.toZec().convertZecToZatoshi()
val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
val memo = "Test Transaction"
val encodedTx = encoder.create(amount, address, memo ?: "")
}
// ///////////////////////////////////////////////////
// Create a signed transaction (with memo) and broadcast
@Test fun submitTransaction() = runBlocking {
val amount = 0.123.toZec().convertZecToZatoshi()
val address = "ztestsapling1tklsjr0wyw0d58f3p7wufvrj2cyfv6q6caumyueadq8qvqt8lda6v6tpx474rfru9y6u75u7qnw"
val memo = "Test Transaction"
val transaction = synchronizer.sendToAddress(amount, address, memo)
log("transaction: $transaction")
}
///////////////////////////////////////////////////////
// Utility Functions
//////////////////////////////////////////////////////
companion object {
private val context = InstrumentationRegistry.getInstrumentation().targetContext
private lateinit var synchronizer: SdkSynchronizer
@BeforeClass
@JvmStatic
fun init() {
Twig.plant(TroubleshootingTwig())
reset()
}
fun log(message: String?) = twig(message ?: "null")
private fun reset() {
context.getDatabasePath(ZcashSdk.DB_DATA_NAME).absoluteFile.delete()
context.getDatabasePath(ZcashSdk.DB_CACHE_NAME).absoluteFile.delete()
}
private fun ByteArray.toHex(): String {
val sb = StringBuilder(size * 2)
for (b in this)
sb.append(String.format("%02x", b))
return sb.toString()
}
}
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cash.z.wallet.sdk.demoapp">
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,4 +1,4 @@
package cash.z.wallet.sdk.sample.address
package cash.z.wallet.sdk.demoapp
import android.app.Application

View File

@ -0,0 +1,29 @@
package cash.z.wallet.sdk.demoapp
import cash.z.wallet.sdk.jni.RustBackend
import cash.z.wallet.sdk.jni.RustBackendWelding
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
* This file represents the dependencies that are specific to this demo. Normally, a dependency
* injection framework like Dagger would provide these objects. For the sake of simplicity, we // TODO finish explaining
*/
object AppInjection {
fun provideRustBackend(prefix: String): RustBackendWelding {
return RustBackend.create(App.instance, "${prefix}_Cache.db", "${prefix}_Data.db")
}
/**
* A sample class that pretends to securely accept a value, store it and return it later. In
* practice, a wallet maker may have a way of securely storing data.
*/
class Vault(var value: String = "") : ReadWriteProperty<Any?, String> {
override fun getValue(thisRef: Any?, property: KProperty<*>): String = value
override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
this.value = value
}
}
}

View File

@ -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.data.TroubleshootingTwig
import cash.z.wallet.sdk.data.Twig
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
abstract class BaseDemoFragment<T : ViewBinding> : 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()
}

View File

@ -0,0 +1,69 @@
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
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()
}
}

View File

@ -0,0 +1,34 @@
package cash.z.wallet.sdk.demoapp.demos.getaddress
import android.view.LayoutInflater
import cash.z.wallet.sdk.demoapp.App
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
import cash.z.wallet.sdk.demoapp.databinding.FragmentGetAddressBinding
import cash.z.wallet.sdk.secure.Wallet
class GetAddressFragment : BaseDemoFragment<FragmentGetAddressBinding>() {
private var seed: ByteArray = App.instance.defaultConfig.seed
private lateinit var wallet: Wallet
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.
*/
wallet = Wallet().also {
it.initialize(App.instance, seed)
}
}
override fun onResetComplete() {
binding.textInfo.text = wallet.getAddress()
}
override fun onClear() {
wallet.clear()
}
}

View File

@ -0,0 +1,50 @@
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<FragmentGetBlockBinding>() {
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()
}
}
//
//for block range, put them in a table and show a list of block heights and vtx count sorted by time
//
// and for this, allow input

View File

@ -0,0 +1,61 @@
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<FragmentGetBlockRangeBinding>() {
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")
}
}
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"
}
}
//
//for block range, put them in a table and show a list of block heights and vtx count sorted by time
//
// and for this, allow input

View File

@ -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<FragmentGetLatestHeightBinding>() {
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()
}
}

View File

@ -0,0 +1,41 @@
package cash.z.wallet.sdk.demoapp.demos.getprivatekey
import android.view.LayoutInflater
import cash.z.wallet.sdk.demoapp.App
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
import cash.z.wallet.sdk.demoapp.databinding.FragmentGetPrivateKeyBinding
import cash.z.wallet.sdk.secure.Wallet
class GetPrivateKeyFragment : BaseDemoFragment<FragmentGetPrivateKeyBinding>() {
private var seed: ByteArray = App.instance.defaultConfig.seed
private lateinit var wallet: Wallet
private lateinit var privateKeys: Array<String>
override fun inflateBinding(layoutInflater: LayoutInflater): FragmentGetPrivateKeyBinding =
FragmentGetPrivateKeyBinding.inflate(layoutInflater)
override fun resetInBackground() {
wallet = Wallet()
/*
* 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.
*
* Since we always clear the wallet, this function call will never return null. Otherwise, we
* would interpret the null case to mean that the wallet data files already exist and
* the private keys were stored externally (i.e. stored securely by the app, not the SDK).
*/
privateKeys = wallet.initialize(App.instance, seed)!!
}
override fun onResetComplete() {
binding.textInfo.text = privateKeys[0]
}
override fun onClear() {
wallet.clear()
}
}

View File

@ -0,0 +1,43 @@
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 androidx.navigation.fragment.NavHostFragment
import cash.z.wallet.sdk.data.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("Visiting the home screen clears the default databases, for sanity sake, because " +
"each demo is intended to be self-contained.")
App.instance.getDatabasePath(ZcashSdk.DB_DATA_NAME).absoluteFile.delete()
App.instance.getDatabasePath(ZcashSdk.DB_CACHE_NAME).absoluteFile.delete()
}
}

View File

@ -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<String>().apply {
value = "\u25c4\tSelect a demo"
}
val text: LiveData<String> = _text
}

View File

@ -0,0 +1,39 @@
package cash.z.wallet.sdk.demoapp.demos.listtransactions
import cash.z.wallet.sdk.data.PagedTransactionRepository
import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.TransactionRepository
import cash.z.wallet.sdk.demoapp.App
import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
import cash.z.wallet.sdk.secure.Wallet
object Injector {
private val appContext = App.instance
private val sampleSeed = App.instance.defaultConfig.seed
private val birthdayHeight: Int = App.instance.defaultConfig.birthdayHeight
private val host: String = App.instance.defaultConfig.host
private fun provideKeyManager(): Wallet.KeyManager {
return SampleStorageBridge().securelyStoreSeed(sampleSeed)
}
private fun provideWallet(keyManager: Wallet.KeyManager): Wallet {
return Wallet().apply {
initialize(appContext, keyManager.seed, birthdayHeight)?.let { privateKeys ->
keyManager.key = privateKeys.first()
}
}
}
fun provideLedger(): PagedTransactionRepository {
return PagedTransactionRepository(appContext, 2)
}
fun provideSynchronizer(ledger: TransactionRepository): Synchronizer {
val keyManager = provideKeyManager()
return Synchronizer(
appContext, provideWallet(keyManager), host, keyManager,
ledger = ledger
)
}
}

View File

@ -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.data.PagedTransactionRepository
import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
import cash.z.wallet.sdk.demoapp.databinding.FragmentListTransactionsBinding
import cash.z.wallet.sdk.entity.ReceivedTransaction
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ReceiveChannel
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<FragmentListTransactionsBinding>() {
private lateinit var ledger: PagedTransactionRepository
private lateinit var synchronizer: Synchronizer
override fun inflateBinding(layoutInflater: LayoutInflater) =
FragmentListTransactionsBinding.inflate(layoutInflater)
override fun resetInBackground() {
ledger = Injector.provideLedger()
synchronizer = Injector.provideSynchronizer(ledger)
}
override fun onResetComplete() {
initTransactionUI()
startSynchronizer()
monitorStatus()
}
override fun onClear() {
ledger.close()
synchronizer.stop()
}
private fun monitorStatus() {
lifecycleScope.launch {
synchronizer.status.collect { onStatus(it) }
}
}
private fun initTransactionUI() {
binding.recyclerTransactions.layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
binding.recyclerTransactions.adapter = TransactionAdapter()
}
private fun startSynchronizer() {
lifecycleScope.apply {
synchronizer.start(this)
launchProgressMonitor(synchronizer.progress())
}
}
private fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel<Int>) = launch {
for (i in channel) {
onProgress(i)
}
}
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
ledger.setTransactionPageListener(this) { t ->
val adapter = binding.recyclerTransactions.adapter as TransactionAdapter
adapter.submitList(t as PagedList<ReceivedTransaction>)
}
}
}

View File

@ -0,0 +1,40 @@
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.ReceivedTransaction
class TransactionAdapter :
PagedListAdapter<ReceivedTransaction, TransactionViewHolder>(
DIFF_CALLBACK
) {
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))
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ReceivedTransaction>() {
override fun areItemsTheSame(
oldItem: ReceivedTransaction,
newItem: ReceivedTransaction
) = oldItem.minedHeight == newItem.minedHeight
override fun areContentsTheSame(
oldItem: ReceivedTransaction,
newItem: ReceivedTransaction
) = oldItem.equals(newItem)
}
}
}

View File

@ -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.ReceivedTransaction
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<TextView>(R.id.text_transaction_amount)
private val timeText = itemView.findViewById<TextView>(R.id.text_transaction_timestamp)
private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
fun bindTo(transaction: ReceivedTransaction?) {
amountText.text = transaction?.value.convertZatoshiToZecString()
timeText.text =
if (transaction == null || transaction?.blockTimeInSeconds == 0L) "Pending"
else formatter.format(transaction.blockTimeInSeconds * 1000L)
}
}

View File

@ -0,0 +1,93 @@
package cash.z.wallet.sdk.demoapp.demos.send
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.lifecycle.coroutineScope
import cash.z.wallet.sdk.data.SdkSynchronizer
import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.demoapp.App
import cash.z.wallet.sdk.demoapp.BaseDemoFragment
import cash.z.wallet.sdk.demoapp.databinding.FragmentSendBinding
import cash.z.wallet.sdk.demoapp.util.SampleStorageBridge
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.convertZecToZatoshi
import cash.z.wallet.sdk.ext.toZec
import cash.z.wallet.sdk.secure.Wallet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.filterNot
import kotlinx.coroutines.launch
class SendFragment : BaseDemoFragment<FragmentSendBinding>() {
private val sampleSeed = App.instance.defaultConfig.seed
private val birthdayHeight: Int = App.instance.defaultConfig.birthdayHeight
private val host: String = App.instance.defaultConfig.host
private lateinit var synchronizer: Synchronizer
override fun inflateBinding(layoutInflater: LayoutInflater): FragmentSendBinding =
FragmentSendBinding.inflate(layoutInflater)
override fun resetInBackground() {
val keyManager = SampleStorageBridge().securelyStoreSeed(sampleSeed)
synchronizer =
Synchronizer(App.instance, host, keyManager, birthdayHeight)
}
override fun onResetComplete() {
lifecycle.coroutineScope.apply {
synchronizer.start(this)
launchProgressMonitor(synchronizer.progress())
launchBalanceMonitor(synchronizer.balances())
}
binding.buttonSend.setOnClickListener(::onSend)
}
override fun onClear() {
// remove the stored databases
(synchronizer as SdkSynchronizer).clearData()
synchronizer.stop()
}
private fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel<Int>) = launch {
for (i in channel) {
onProgress(i)
}
}
private fun CoroutineScope.launchBalanceMonitor(
channel: ReceiveChannel<Wallet.WalletBalance>
) = launch {
val positiveBalances = channel.filterNot { it.total < 0 }
for (i in positiveBalances) {
onBalance(i)
}
}
private fun onProgress(i: Int) {
val message = when (i) {
100 -> "Scanning blocks..."
else -> "Downloading blocks...$i%"
}
binding.textStatus.text = message
}
private fun onBalance(balance: Wallet.WalletBalance) {
binding.textBalances.text = """
Available balance: ${balance.available.convertZatoshiToZecString()}
Total balance: ${balance.total.convertZatoshiToZecString()}
""".trimIndent()
binding.buttonSend.isEnabled = balance.available > 0
binding.textStatus.text = "Synced!"
}
private fun onSend(unused: View) {
// TODO: add input fields to the UI. Possibly, including a scanner for the address input
lifecycleScope.launch {
synchronizer.sendToAddress(0.001.toZec().convertZecToZatoshi(), "ztestsapling1fg82ar8y8whjfd52l0xcq0w3n7nn7cask2scp9rp27njeurr72ychvud57s9tu90fdqgwdt07lg", "Demo App Funds")
}
Toast.makeText(App.instance, "Sending funds...", Toast.LENGTH_SHORT).show()
}
}

View File

@ -0,0 +1,58 @@
package cash.z.wallet.sdk.demoapp.util
import android.content.Context
import cash.z.wallet.sdk.demoapp.App
import cash.z.wallet.sdk.secure.Wallet
@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 KeyManager interface. This class implements the interface by delegating to the storage
* object. For demo purposes, we're using an insecure SampleStorage implementation but this can
* easily be swapped for a true storage solution.
*/
class SampleStorageBridge(): Wallet.KeyManager {
private val KEY_SEED = "cash.z.wallet.sdk.demoapp.SEED"
private val KEY_PK = "cash.z.wallet.sdk.demoapp.PK"
private val delegate = SampleStorage()
constructor(seed: ByteArray) : this() {
securelyStoreSeed(seed)
}
fun securelyStoreSeed(seed: ByteArray): SampleStorageBridge {
delegate.saveSensitiveBytes(KEY_SEED, seed)
return this
}
override val seed: ByteArray get() = delegate.loadSensitiveBytes(KEY_SEED)!!
override var key: String
get() = delegate.loadSensitiveString(KEY_PK)!!
set(value) {
delegate.saveSensitiveString(KEY_PK, value)
}
}

View File

@ -0,0 +1,31 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
android:width="108dp">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
</vector>

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
android:width="108dp">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM3,9h2L5,7L3,7v2zM7,13h14v-2L7,11v2zM7,17h14v-2L7,15v2zM7,7v2h14L21,7L7,7z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,11H5V13H3V11M11,5H13V9H11V5M9,11H13V15H11V13H9V11M15,11H17V13H19V11H21V13H19V15H21V19H19V21H17V19H13V21H11V17H15V15H17V13H15V11M19,19V15H17V19H19M15,3H21V9H15V3M17,5V7H19V5H17M3,3H9V9H3V3M5,5V7H7V5H5M3,15H9V21H3V15M5,17V19H7V17H5Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,6h12v12H6z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7.77,6.76L6.23,5.48 0.82,12l5.41,6.52 1.54,-1.28L3.42,12l4.35,-5.24zM7,13h2v-2L7,11v2zM17,11h-2v2h2v-2zM11,13h2v-2h-2v2zM17.77,5.48l-1.54,1.28L20.58,12l-4.35,5.24 1.54,1.28L23.18,12l-5.41,-6.52z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,8l-4,4h3c0,3.31 -2.69,6 -6,6 -1.01,0 -1.97,-0.25 -2.8,-0.7l-1.46,1.46C8.97,19.54 10.43,20 12,20c4.42,0 8,-3.58 8,-8h3l-4,-4zM6,12c0,-3.31 2.69,-6 6,-6 1.01,0 1.97,0.25 2.8,0.7l1.46,-1.46C15.03,4.46 13.57,4 12,4c-4.42,0 -8,3.58 -8,8H1l4,4 4,-4H6z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13,12h7v1.5h-7zM13,9.5h7L20,11h-7zM13,14.5h7L20,16h-7zM21,4L3,4c-1.1,0 -2,0.9 -2,2v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,6c0,-1.1 -0.9,-2 -2,-2zM21,19h-9L12,6h9v13z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF66BB6A" android:pathData="M20,5.41L18.59,4 7,15.59V9H5v10h10v-2H8.41z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFEF5350" android:pathData="M9,5v2h6.59L4,18.59 5.41,20 17,8.41V15h2V5z"/>
</vector>

View File

@ -0,0 +1,10 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear" />
</shape>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="@layout/app_bar_main" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cash.z.wallet.sdk.demoapp.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_floating_action" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_main">
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cash.z.wallet.sdk.demoapp.demos.gallery.GalleryFragment">
<TextView
android:id="@+id/text_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="20sp"
android:text="loading address..."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_block_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/button_apply"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_block_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="8"
android:hint="block height"
android:inputType="number"
android:text="500000"
android:textSize="20sp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_apply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="apply"
app:layout_constraintBottom_toBottomOf="@id/text_layout_block_height"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_layout_block_height"
app:layout_constraintTop_toTopOf="@id/text_layout_block_height" />
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="loading block..."
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_layout_block_height" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_start_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/text_layout_end_height"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_start_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="start height"
android:inputType="number"
android:maxLength="7"
android:text="500000"
android:textSize="20sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_end_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/button_apply"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/text_layout_start_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_end_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="end height"
android:inputType="number"
android:maxLength="7"
android:text="500000"
android:textSize="20sp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_apply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:text="apply"
app:layout_constraintBottom_toBottomOf="@id/text_layout_end_height"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_layout_end_height"
app:layout_constraintTop_toTopOf="@id/text_layout_end_height" />
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="loading blocks..."
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_layout_end_height" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="20sp"
android:text="loading latest height..."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="20sp"
android:text="loading keys soon..."
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cash.z.wallet.sdk.demoapp.demos.home.HomeFragment">
<TextView
android:id="@+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@id/button_home"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_home" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cash.z.wallet.sdk.demoapp.demos.home.HomeSecondFragment">
<TextView
android:id="@+id/textview_home_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="@id/button_home_second"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_home_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/previous"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textview_home_second" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_start_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/text_layout_end_height"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_end_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/text_layout_start_height"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<TextView
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:padding="8dp"
android:text="Initializing..."
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/text_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="loading blocks..."
android:textSize="20sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_status"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_transactions"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="32dp"
app:layout_constraintTop_toBottomOf="@id/text_info"
app:layout_constraintStart_toStartOf="parent"
tools:itemCount="15"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_transaction"
tools:orientation="vertical" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/text_layout_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/button_send"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/text_block_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="8"
android:hint="amount"
android:inputType="number"
android:textSize="20sp" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text="Send"
app:layout_constraintBottom_toBottomOf="@id/text_layout_amount"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_layout_amount"
app:layout_constraintTop_toTopOf="@id/text_layout_amount" />
<TextView
android:id="@+id/text_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="32dp"
android:text="Initializing wallet..."
app:layout_constraintStart_toStartOf="@id/text_layout_amount"
app:layout_constraintTop_toBottomOf="@id/text_layout_amount" />
<TextView
android:id="@+id/text_balances"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="@id/text_status"
app:layout_constraintTop_toBottomOf="@id/text_status"
android:text="Available balance: --\nTotal balance: --" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cash.z.wallet.sdk.demoapp.demos.slideshow.SlideshowFragment">
<TextView
android:id="@+id/text_slideshow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container_transaction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F0F0F0"
android:elevation="1dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingEnd="10dp"
android:paddingStart="8dp"
android:layout_marginTop="4dp"
tools:ignore="RtlSymmetry">
<ImageView
android:id="@+id/image_transaction_type"
android:layout_width="40dp"
android:layout_height="40dp"
app:srcCompat="@drawable/ic_receive"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_transaction_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/text_transaction_address"
app:layout_constraintStart_toEndOf="@id/image_transaction_type"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="8/23 3:24pm" />
<TextView
android:id="@+id/text_transaction_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="12sp"
android:paddingEnd="16dp"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintEnd_toStartOf="@id/text_transaction_amount"
app:layout_constraintStart_toStartOf="@id/text_transaction_timestamp"
app:layout_constraintTop_toBottomOf="@id/text_transaction_timestamp"
app:layout_constraintBottom_toBottomOf="parent"
android:text="funds received" />
<TextView
android:id="@+id/text_transaction_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="+ 4.244"
android:textColor="@color/colorPrimary"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/nav_header_desc"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle" />
</LinearLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_home"
android:icon="@drawable/ic_menu_home"
android:title="@string/menu_home" />
<item
android:id="@+id/nav_private_key"
android:icon="@drawable/ic_menu_private_key"
android:title="@string/menu_private_key" />
<item
android:id="@+id/nav_address"
android:icon="@drawable/ic_menu_address"
android:title="@string/menu_address" />
<item
android:id="@+id/nav_latest_height"
android:icon="@drawable/ic_menu_latest_height"
android:title="@string/menu_latest_height" />
<item
android:id="@+id/nav_block"
android:icon="@drawable/ic_menu_block"
android:title="@string/menu_block" />
<item
android:id="@+id/nav_block_range"
android:icon="@drawable/ic_menu_block_range"
android:title="@string/menu_block_range" />
<item
android:id="@+id/nav_transactions"
android:icon="@drawable/ic_list"
android:title="@string/menu_transactions" />
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_menu_send"
android:title="@string/menu_send" />
</group>
</menu>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<adaptive-icon
xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<adaptive-icon
xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/nav_home">
<fragment
android:id="@+id/nav_home"
android:name="cash.z.wallet.sdk.demoapp.demos.home.HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_home">
</fragment>
<fragment
android:id="@+id/nav_address"
android:name="cash.z.wallet.sdk.demoapp.demos.getaddress.GetAddressFragment"
android:label="@string/menu_address"
tools:layout="@layout/fragment_get_address" />
<fragment
android:id="@+id/nav_private_key"
android:name="cash.z.wallet.sdk.demoapp.demos.getprivatekey.GetPrivateKeyFragment"
android:label="@string/menu_private_key"
tools:layout="@layout/fragment_get_private_key" />
<fragment
android:id="@+id/nav_latest_height"
android:name="cash.z.wallet.sdk.demoapp.demos.getlatestheight.GetLatestHeightFragment"
android:label="@string/menu_latest_height"
tools:layout="@layout/fragment_get_latest_height" />
<fragment
android:id="@+id/nav_block"
android:name="cash.z.wallet.sdk.demoapp.demos.getblock.GetBlockFragment"
android:label="@string/menu_block"
tools:layout="@layout/fragment_get_block" />
<fragment
android:id="@+id/nav_block_range"
android:name="cash.z.wallet.sdk.demoapp.demos.getblockrange.GetBlockRangeFragment"
android:label="@string/menu_block_range"
tools:layout="@layout/fragment_get_block_range" />
<fragment
android:id="@+id/nav_transactions"
android:name="cash.z.wallet.sdk.demoapp.demos.listtransactions.ListTransactionsFragment"
android:label="@string/menu_transactions"
tools:layout="@layout/fragment_list_transactions" />
<fragment
android:id="@+id/nav_send"
android:name="cash.z.wallet.sdk.demoapp.demos.send.SendFragment"
android:label="@string/menu_send"
tools:layout="@layout/fragment_send" />
</navigation>

View File

@ -0,0 +1,8 @@
<resources>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,24 @@
<resources>
<string name="app_name">Demo App</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="nav_header_title">Android SDK Demo</string>
<string name="nav_header_subtitle">v1.0.0-alpha02</string>
<string name="nav_header_desc">Navigation header</string>
<string name="action_settings">Settings</string>
<!-- Drawer Menu -->
<string name="menu_home">Home</string>
<string name="menu_private_key">Get Private Key</string>
<string name="menu_address">Get Address</string>
<string name="menu_latest_height">Get Latest Height</string>
<string name="menu_block">Get Block</string>
<string name="menu_block_range">Get Block Range</string>
<string name="menu_decrypt">Decrypt Block</string>
<string name="menu_transactions">List Transactions</string>
<string name="menu_send">Send</string>
<string name="home_second">Home Second</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More