First run screen is functional

This commit is contained in:
Kevin Gorham 2019-02-04 02:08:26 -05:00 committed by Kevin Gorham
parent 9a45b5e242
commit 6a8cc9bc6c
20 changed files with 499 additions and 183 deletions

View File

@ -85,10 +85,10 @@ internal object SynchronizerModule {
// TODO: load most of these properties in later, perhaps from settings // TODO: load most of these properties in later, perhaps from settings
object Properties { object Properties {
const val COMPACT_BLOCK_SERVER = "10.0.2.2" // const val COMPACT_BLOCK_SERVER = "10.0.0.26"
// const val COMPACT_BLOCK_SERVER = "lightwalletd.z.cash" const val COMPACT_BLOCK_SERVER = "lightwalletd.z.cash"
const val COMPACT_BLOCK_PORT = 9067 const val COMPACT_BLOCK_PORT = 9067
const val CACHE_DB_NAME = "wallet_cache.db" const val CACHE_DB_NAME = "wallet_cache9.db"
const val DATA_DB_NAME = "wallet_data.db" const val DATA_DB_NAME = "wallet_data9.db"
val SEED_PROVIDER = SampleSeedProvider("dummyseed") val SEED_PROVIDER = SampleSeedProvider("dummyseed")
} }

View File

@ -0,0 +1,46 @@
package cash.z.android.wallet.ui.activity
import android.os.Bundle
import androidx.fragment.app.Fragment
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasFragmentInjector
import dagger.android.support.DaggerAppCompatActivity
import dagger.android.support.HasSupportFragmentInjector
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
abstract class BaseMainActivity : DaggerAppCompatActivity(), CoroutineScope, HasFragmentInjector,
HasSupportFragmentInjector {
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
@Inject
lateinit var supportFragmentInjector: DispatchingAndroidInjector<Fragment>
@Inject
lateinit var frameworkFragmentInjector: DispatchingAndroidInjector<android.app.Fragment>
override fun onCreate(savedInstanceState: Bundle?) {
job = Job()
super.onCreate(savedInstanceState)
}
override fun supportFragmentInjector(): AndroidInjector<androidx.fragment.app.Fragment>? {
return supportFragmentInjector
}
override fun fragmentInjector(): AndroidInjector<android.app.Fragment>? {
return frameworkFragmentInjector
}
}

View File

@ -1,6 +1,8 @@
package cash.z.android.wallet.ui.activity package cash.z.android.wallet.ui.activity
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.view.inputmethod.InputMethodManager.HIDE_NOT_ALWAYS import android.view.inputmethod.InputMethodManager.HIDE_NOT_ALWAYS
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
@ -23,7 +25,14 @@ import dagger.android.support.DaggerAppCompatActivity
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.nav_header_main.* import kotlinx.android.synthetic.main.nav_header_main.*
import cash.z.wallet.sdk.data.Synchronizer import cash.z.wallet.sdk.data.Synchronizer
import com.google.android.material.snackbar.Snackbar
import dagger.android.AndroidInjection
import kotlinx.android.synthetic.main.activity_main_first_run.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
class MainActivity : BaseActivity() { class MainActivity : BaseActivity() {

View File

@ -14,6 +14,7 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.transition.Transition import androidx.transition.Transition
@ -39,6 +40,9 @@ import kotlinx.android.synthetic.main.include_home_header.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.random.Random import kotlin.random.Random
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main_first_run.*
import kotlin.random.nextLong
/** /**
@ -75,11 +79,7 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// setActiveTransactionsShown(false) // setActiveTransactionsShown(false)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(home_toolbar)
mainActivity.setupNavigation()
mainActivity.supportActionBar?.setTitle(R.string.destination_title_home)
}
headerFullViews = arrayOf(text_balance_usd, text_balance_includes_info, text_balance_zec, image_zec_symbol_balance_shadow, image_zec_symbol_balance) headerFullViews = arrayOf(text_balance_usd, text_balance_includes_info, text_balance_zec, image_zec_symbol_balance_shadow, image_zec_symbol_balance)
headerEmptyViews = arrayOf(text_balance_zec_info, text_balance_zec_empty, image_zec_symbol_balance_shadow_empty, image_zec_symbol_balance_empty) headerEmptyViews = arrayOf(text_balance_zec_info, text_balance_zec_empty, image_zec_symbol_balance_shadow_empty, image_zec_symbol_balance_empty)
@ -89,23 +89,44 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
group_empty_view_items.visibility = View.GONE group_empty_view_items.visibility = View.GONE
group_full_view_items.visibility = View.GONE group_full_view_items.visibility = View.GONE
if (MainActivity.DEV_MODE) {
image_logo.setOnClickListener { image_logo.setOnClickListener {
if (MainActivity.DEV_MODE) {
mainActivity.navController.navigate(R.id.nav_send_fragment) mainActivity.navController.navigate(R.id.nav_send_fragment)
// forceRedraw() // forceRedraw()
// toggleViews(false) // toggleViews(false)
} else {
forceRedraw()
toggleViews(false)
} }
} }
button_active_transaction_cancel.setOnClickListener { button_active_transaction_cancel.setOnClickListener {
onCancelActiveTransaction() onCancelActiveTransaction()
} }
refresh_layout.setOnRefreshListener {
val fauxRefresh = Random.nextLong(750L..3000L)
refresh_layout.postDelayed({
refresh_layout.isRefreshing = false
}, fauxRefresh)
}
if (mainActivity.synchronizer.processor.dataDbExists) {
container_first_run.visibility = View.GONE
mainActivity.findViewById<DrawerLayout>(R.id.drawer_layout).setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
sd_fab.visibility = View.VISIBLE
} else {
container_first_run.visibility = View.VISIBLE
mainActivity.findViewById<DrawerLayout>(R.id.drawer_layout).setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
sd_fab.visibility = View.GONE
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val isEmpty = (recycler_transactions?.adapter?.itemCount ?: 0).let { it == 0 } // val isEmpty = (recycler_transactions?.adapter?.itemCount ?: 0).let { it == 0 }
// Log.e("TWIG-t", "Resuming and isEmpty == $isEmpty") // Log.e("TWIG-t", "Resuming and isEmpty == $isEmpty")
// toggleViews(isEmpty) // toggleViews(isEmpty)
@ -121,6 +142,12 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(home_toolbar)
mainActivity.setupNavigation()
mainActivity.supportActionBar?.setTitle(R.string.destination_title_home)
}
homePresenter = HomePresenter(this, mainActivity.synchronizer) homePresenter = HomePresenter(this, mainActivity.synchronizer)
initFab(activity!!) initFab(activity!!)
@ -175,6 +202,12 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
snackbar?.setText(message) snackbar?.setText(message)
if(progress == 100 && snackbar?.isShownOrQueued != true) snackbar?.show() if(progress == 100 && snackbar?.isShownOrQueued != true) snackbar?.show()
} }
if (progress >= 100) {
container_first_run.visibility = View.GONE
mainActivity.findViewById<DrawerLayout>(R.id.drawer_layout).setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
sd_fab.visibility = View.VISIBLE
}
} }
override fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) { override fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
@ -206,6 +239,8 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
button_active_transaction_cancel.text = "${transaction.value/1000L}" button_active_transaction_cancel.text = "${transaction.value/1000L}"
} }
is TransactionState.Failure -> { is TransactionState.Failure -> {
lottie_active_transaction.setAnimation(R.raw.lottie_send_failure)
lottie_active_transaction.playAnimation()
title = "Failed" title = "Failed"
subtitle = when(transactionState.failedStep) { subtitle = when(transactionState.failedStep) {
TransactionState.Creating -> "Failed to create transaction" TransactionState.Creating -> "Failed to create transaction"
@ -216,8 +251,14 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
onCancelActiveTransaction() onCancelActiveTransaction()
} }
is TransactionState.AwaitingConfirmations -> { is TransactionState.AwaitingConfirmations -> {
if (transactionState.confirmationCount < 1) {
lottie_active_transaction.setAnimation(R.raw.lottie_send_success)
lottie_active_transaction.playAnimation()
title = "ZEC Sent" title = "ZEC Sent"
subtitle = "Awaiting Confirmations (${transactionState.confirmationCount}/10)" subtitle = "Awaiting Confirmations (${transactionState.confirmationCount}/10)"
} else {
// play confirmation counting animation
}
} }
} }
text_active_transaction_title.text = title text_active_transaction_title.text = title
@ -305,11 +346,14 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
private fun onActiveTransactionTransitionEnd() { private fun onActiveTransactionTransitionEnd() {
// fixes a bug where the translation gets lost, during animation. As a nice side effect, visually, it makes the view appear to settle in to position // fixes a bug where the translation gets lost, during animation. As a nice side effect, visually, it makes the view appear to settle in to position
header_active_transaction.translationZ = 10.0f header_active_transaction.translationZ = 10.0f
button_active_transaction_cancel.apply {
postDelayed({text = "cancel"}, 50L)
}
} }
private fun onCancelActiveTransaction() { private fun onCancelActiveTransaction() {
button_active_transaction_cancel.isEnabled = false button_active_transaction_cancel.isEnabled = false
button_active_transaction_cancel.text = "canceled" button_active_transaction_cancel.text = "cancel"
header_active_transaction.animate().apply { header_active_transaction.animate().apply {
translationZ(0f) translationZ(0f)
duration = 200L duration = 200L
@ -330,7 +374,6 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
} ) } )
} }
homePresenter.onCancelActiveTransaction() homePresenter.onCancelActiveTransaction()
} }

View File

@ -4,26 +4,25 @@ import android.util.Log
import cash.z.android.wallet.extention.Toaster import cash.z.android.wallet.extention.Toaster
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.android.wallet.vo.WalletTransaction import cash.z.android.wallet.vo.WalletTransaction
import cash.z.android.wallet.vo.WalletTransactionStatus
import cash.z.android.wallet.vo.WalletTransactionStatus.RECEIVED import cash.z.android.wallet.vo.WalletTransactionStatus.RECEIVED
import cash.z.android.wallet.vo.WalletTransactionStatus.SENT import cash.z.android.wallet.vo.WalletTransactionStatus.SENT
import cash.z.wallet.sdk.data.ActiveTransaction import cash.z.wallet.sdk.data.ActiveTransaction
import cash.z.wallet.sdk.data.Synchronizer import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.TransactionState import cash.z.wallet.sdk.data.TransactionState
import cash.z.wallet.sdk.vo.NoteQuery import cash.z.wallet.sdk.vo.NoteQuery
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.math.BigDecimal import java.math.BigDecimal
import kotlin.coroutines.CoroutineContext
class HomePresenter( class HomePresenter(
private val view: HomeView, private val view: HomeView,
private val synchronizer: Synchronizer private val synchronizer: Synchronizer
) : Presenter { ) : Presenter, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
interface HomeView : PresenterView { interface HomeView : PresenterView {
fun setTransactions(transactions: List<WalletTransaction>) fun setTransactions(transactions: List<WalletTransaction>)
@ -32,32 +31,20 @@ class HomePresenter(
fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>)
} }
private var balanceJob: Job? = null
private var transactionJob: Job? = null
private var progressJob: Job? = null
private var activeTransactionJob: Job? = null
override suspend fun start() { override suspend fun start() {
Log.e("@TWIG-t", "homePresenter starting!") Log.e("@TWIG-t", "homePresenter starting!")
with(view) { launchBalanceBinder(synchronizer.repository.balance())
balanceJob = launchBalanceBinder(synchronizer.repository.balance()) launchTransactionBinder(synchronizer.repository.allTransactions())
transactionJob = launchTransactionBinder(synchronizer.repository.allTransactions()) launchProgressMonitor(synchronizer.downloader.progress())
progressJob = launchProgressMonitor(synchronizer.downloader.progress()) launchActiveTransactionMonitor(synchronizer.activeTransactions())
activeTransactionJob = launchActiveTransactionMonitor(synchronizer.activeTransactions())
}
} }
override fun stop() { override fun stop() {
Log.e("@TWIG-t", "homePresenter stopping!") Log.e("@TWIG-t", "homePresenter stopping!")
job.cancel()
// using nullsafe 'also' to only set these to null when they weren't already null
balanceJob?.cancel()?.also { balanceJob = null }
transactionJob?.cancel()?.also { transactionJob = null }
progressJob?.cancel()?.also { progressJob = null }
activeTransactionJob?.cancel()?.also { progressJob = null }
} }
fun CoroutineScope.launchBalanceBinder(channel: ReceiveChannel<Long>) = launch { private fun CoroutineScope.launchBalanceBinder(channel: ReceiveChannel<Long>) = launch {
var old: Long? = null var old: Long? = null
Log.e("@TWIG-t", "balance binder starting!") Log.e("@TWIG-t", "balance binder starting!")
for (new in channel) { for (new in channel) {
@ -67,7 +54,7 @@ class HomePresenter(
Log.e("@TWIG", "balance binder exiting!") Log.e("@TWIG", "balance binder exiting!")
} }
fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<NoteQuery>>) = launch { private fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<NoteQuery>>) = launch {
Log.e("@TWIG", "transaction binder starting!") Log.e("@TWIG", "transaction binder starting!")
for (noteQueryList in channel) { for (noteQueryList in channel) {
Log.e("@TWIG", "received ${noteQueryList.size} transactions for presenting") Log.e("@TWIG", "received ${noteQueryList.size} transactions for presenting")
@ -81,14 +68,15 @@ class HomePresenter(
private suspend fun updateTimeStamp(noteQuery: NoteQuery) = synchronizer.updateTimeStamp(noteQuery.height) private suspend fun updateTimeStamp(noteQuery: NoteQuery) = synchronizer.updateTimeStamp(noteQuery.height)
fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel<Int>) = launch { private fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel<Int>) = launch {
Log.e("@TWIG", "progress monitor starting on thread ${Thread.currentThread().name}!")
for (i in channel) { for (i in channel) {
bind(i) bind(i)
} }
Log.e("@TWIG", "progress monitor exiting!") Log.e("@TWIG", "progress monitor exiting!")
} }
fun CoroutineScope.launchActiveTransactionMonitor(channel: ReceiveChannel<Map<ActiveTransaction, TransactionState>>) = launch { private fun CoroutineScope.launchActiveTransactionMonitor(channel: ReceiveChannel<Map<ActiveTransaction, TransactionState>>) = launch {
Log.e("@TWIG-v", "active transaction monitor starting!") Log.e("@TWIG-v", "active transaction monitor starting!")
for (i in channel) { for (i in channel) {
bind(i) bind(i)
@ -96,20 +84,26 @@ class HomePresenter(
Log.e("@TWIG-v", "active transaction monitor exiting!") Log.e("@TWIG-v", "active transaction monitor exiting!")
} }
private fun bind(old: Long?, new: Long) {
//
// View Callbacks on Main Thread
//
private fun bind(old: Long?, new: Long) = onMain {
Log.e("@TWIG-t", "binding balance of $new") Log.e("@TWIG-t", "binding balance of $new")
view.updateBalance(old ?: 0L, new) view.updateBalance(old ?: 0L, new)
} }
private fun bind(transactions: List<WalletTransaction>) {
private fun bind(transactions: List<WalletTransaction>) = onMain {
Log.e("@TWIG-t", "binding ${transactions.size} walletTransactions") Log.e("@TWIG-t", "binding ${transactions.size} walletTransactions")
view.setTransactions(transactions) view.setTransactions(transactions)
} }
private fun bind(progress: Int) { private fun bind(progress: Int) = onMain {
view.showProgress(progress) view.showProgress(progress)
if(progress == 100) { if (progress == 100) {
view.launch { launch {
// TODO: remove this behavior and pull it down into the synchronizer // TODO: remove this behavior and pull it down into the synchronizer
Log.e("@TWIG-t", "triggering manual scan!") Log.e("@TWIG-t", "triggering manual scan!")
synchronizer.processor.scanBlocks() synchronizer.processor.scanBlocks()
@ -117,24 +111,29 @@ class HomePresenter(
} }
} }
private fun bind(activeTransactionMap: Map<ActiveTransaction, TransactionState>) { private fun bind(activeTransactionMap: Map<ActiveTransaction, TransactionState>) = onMain {
Log.e("@TWIG-v", "binding a.t. map of size ${activeTransactionMap.size}") Log.e("@TWIG-v", "binding a.t. map of size ${activeTransactionMap.size}")
if (activeTransactionMap.isNotEmpty()) view.setActiveTransactions(activeTransactionMap) if (activeTransactionMap.isNotEmpty()) view.setActiveTransactions(activeTransactionMap)
} }
fun onCancelActiveTransaction() { fun onCancelActiveTransaction() {
// TODO: hold a reference to the job and cancel it // TODO: hold a reference to the job and cancel it
Toaster.short("Cancelled transaction!") Toaster.short("Cancelled transaction!")
} }
private fun onMain(block: () -> Unit) = launch {
withContext(Main) {
Log.e("@TWIG-t", "running task on main thread - start ${coroutineContext[Job]} | ${coroutineContext[CoroutineName]}")
block()
Log.e("@TWIG-t", "running task on main thread - complete")
}
}
private fun NoteQuery.toWalletTransaction(timeOverride: Long? = null): WalletTransaction { private fun NoteQuery.toWalletTransaction(timeOverride: Long? = null): WalletTransaction {
// convert time from seconds to milliseconds // convert time from seconds to milliseconds
val timestamp = if (timeOverride == null) time * 1000 else timeOverride * 1000 val timestamp = if (timeOverride == null) time * 1000 else timeOverride * 1000
Log.e("@TWIG-u", "setting timestamp to $timestamp for value $value") Log.e("@TWIG-u", "setting timestamp to $timestamp for value $value")
return WalletTransaction(height, if (sent) SENT else RECEIVED, timestamp, BigDecimal(value / 1e8)) return WalletTransaction(height, if (sent) SENT else RECEIVED, timestamp, BigDecimal(value / 1e8))
} }
} }

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cash.z.android.wallet.ui.util
import android.content.Context
import android.util.AttributeSet
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.viewpager.widget.ViewPager
class ViewpagerHeader @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
val numPages = 3
progress = (position + positionOffset) / (numPages - 1)
}
override fun onPageSelected(position: Int) {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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_first_run"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="#81CAFF">
<cash.z.android.wallet.ui.util.ViewpagerHeader
android:layout_width="match_parent"
android:layout_height="230dp"
app:layoutDescription="@xml/scene_15"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:id="@+id/mountains"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/mountains" />
<ImageView
android:id="@+id/trees1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trees"
tools:layout_editor_absoluteX="23dp"
tools:layout_editor_absoluteY="130dp" />
<ImageView
android:id="@+id/trees2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trees"
tools:layout_editor_absoluteX="7dp"
tools:layout_editor_absoluteY="98dp" />
<ImageView
android:id="@+id/car"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/car"
tools:layout_editor_absoluteX="7dp"
tools:layout_editor_absoluteY="194dp" />
</cash.z.android.wallet.ui.util.ViewpagerHeader>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -37,4 +37,6 @@
app:layout_anchor="@id/home_app_bar" app:layout_anchor="@id/home_app_bar"
app:layout_anchorGravity="bottom|center" app:layout_anchorGravity="bottom|center"
app:srcCompat="@drawable/ic_zcashlogo_badge" /> app:srcCompat="@drawable/ic_zcashlogo_badge" />
<include layout="@layout/activity_main_first_run"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -9,6 +9,11 @@
android:fillViewport="true" android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content_home" android:id="@+id/content_home"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -40,7 +45,7 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true" app:lottie_autoPlay="true"
app:lottie_loop="false" app:lottie_loop="false"
app:lottie_rawRes="@raw/lottie_active_transaction_fail" /> app:lottie_rawRes="@raw/lottie_send_common" />
<TextView <TextView
android:id="@+id/text_active_transaction_title" android:id="@+id/text_active_transaction_title"
@ -151,5 +156,5 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:constraint_referenced_ids="image_empty_wallet,text_wallet_message" /> app:constraint_referenced_ids="image_empty_wallet,text_wallet_message" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000"
motion:interpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/car"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight" />
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@id/mountains"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:translationX="10dp"
android:scaleX="1.2"
android:scaleY="1.2"
motion:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/trees1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginBottom="60dp"
motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
<Constraint
android:id="@id/trees2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="90dp"
android:layout_marginBottom="30dp"
motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
<Constraint
android:id="@id/car"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginBottom="8dp"
motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@id/mountains"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:translationX="-10dp"
android:scaleX="1.2"
android:scaleY="1.2"
motion:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/trees1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginBottom="60dp"
motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
<Constraint
android:id="@id/trees2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginBottom="30dp"
motion:layout_constraintLeft_toLeftOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
<Constraint
android:id="@id/car"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_marginBottom="8dp"
motion:layout_constraintRight_toRightOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"/>
</ConstraintSet>
</Transition>
</MotionScene>