Consolidate old sample apps into new demo app.
|
@ -1 +0,0 @@
|
||||||
/build
|
|
|
@ -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'
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 15 KiB |
|
@ -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>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<resources>
|
|
||||||
<string name="app_name">Zcash Address</string>
|
|
||||||
</resources>
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
include ':app', ":sdk"
|
|
||||||
project(":sdk").projectDir = file("../../../zcash-android-wallet-sdk")
|
|
||||||
rootProject.name='Zcash Address'
|
|
|
@ -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!
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -1,4 +1,4 @@
|
||||||
package cash.z.wallet.sdk.sample.address
|
package cash.z.wallet.sdk.demoapp
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 16 KiB |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|