changes before adding mock buildType

This commit is contained in:
Kevin Gorham 2019-02-14 20:26:56 -05:00 committed by Kevin Gorham
parent ad708e69d5
commit e27e10315a
18 changed files with 1026 additions and 535 deletions

View File

@ -0,0 +1,19 @@
package cash.z.android.wallet.extention
import android.view.View
import cash.z.android.wallet.R
import com.google.android.material.snackbar.Snackbar
/**
* Show a snackbar with an "OK" button
*/
internal inline fun Snackbar?.showOk(view: View, message: String): Snackbar {
return if (this == null) {
Snackbar.make(view, "$message", Snackbar.LENGTH_INDEFINITE)
.setAction(view.context.getString(R.string.ok_allcaps)){/*auto-close*/}
} else {
setText(message)
}.also {
if (!it.isShownOrQueued) it.show()
}
}

View File

@ -7,7 +7,7 @@ object AliceWallet {
val seedProvider = SampleSeedProvider(name)
val spendingKeyProvider = SampleSpendingKeySharedPref(name)
const val cacheDbName = "testalice_cache.db"
const val dataDbName = "testalice_data.db"
const val dataDbName = "testalice_data8.db"
}
object BobWallet {
@ -15,8 +15,8 @@ object BobWallet {
val seedProvider =
SampleSeedProvider(name)
val spendingKeyProvider = SampleSpendingKeySharedPref(name)
const val cacheDbName = "testalice_cache.db"
const val dataDbName = "testalice_data.db"
const val cacheDbName = "testbob_cache.db"
const val dataDbName = "testbob_data.db"
}
object MyWallet {
@ -41,4 +41,12 @@ object SampleProperties {
val COMPACT_BLOCK_SERVER = Servers.EMULATOR.host
const val COMPACT_BLOCK_PORT = 9067
val wallet = AliceWallet
// TODO: placeholder until we have a network service for this
const val USD_PER_ZEC = 49.07
/**
* A simple flag that helps with removing shortcuts in the code used during development.
* TODO: either elevate this to a real thing (based off a system property or some such) or delete it!
*/
const val DEV_MODE = false
}

View File

@ -20,6 +20,7 @@ import androidx.navigation.ui.setupWithNavController
import cash.z.android.wallet.BuildConfig
import cash.z.android.wallet.R
import cash.z.android.wallet.ZcashWalletApplication
import cash.z.android.wallet.sample.SampleProperties.DEV_MODE
import dagger.Module
import dagger.android.ContributesAndroidInjector
import dagger.android.support.DaggerAppCompatActivity
@ -53,7 +54,7 @@ class MainActivity : BaseActivity() {
override fun onDestroy() {
super.onDestroy()
synchronizer.stop()
if(!DEV_MODE)synchronizer.stop()
}
override fun onBackPressed() {
@ -66,7 +67,7 @@ class MainActivity : BaseActivity() {
override fun onResume() {
super.onResume()
if(DEV_MODE) navController.navigate(R.id.nav_send_fragment)
// if(DEV_MODE) navController.navigate(R.id.nav_send_fragment)
}
/**
@ -104,14 +105,6 @@ class MainActivity : BaseActivity() {
}
companion object {
/**
* A simple flag that helps with removing shortcuts in the code used during development.
* TODO: either elevate this to a real thing (based off a system property or some such) or delete it!
*/
const val DEV_MODE = false
// TODO: placeholder until we have a network service for this
const val USD_PER_ZEC = 49.07
init {
// Enable vector drawable magic
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)

View File

@ -1,12 +1,10 @@
package cash.z.android.wallet.ui.fragment
import android.app.Activity
import android.os.Bundle
import android.text.SpannableString
import android.text.Spanned
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateInterpolator
@ -15,19 +13,21 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.transition.Transition
import androidx.transition.TransitionInflater
import cash.z.android.wallet.R
import cash.z.android.wallet.extention.Toaster
import cash.z.android.wallet.extention.toAppColor
import cash.z.android.wallet.extention.toAppString
import cash.z.android.wallet.extention.tryIgnore
import cash.z.android.wallet.ui.activity.MainActivity
import cash.z.android.wallet.databinding.FragmentHomeBinding
import cash.z.android.wallet.extention.*
import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.sample.SampleProperties.DEV_MODE
import cash.z.android.wallet.ui.adapter.TransactionAdapter
import cash.z.android.wallet.ui.presenter.HomePresenter
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
import cash.z.android.wallet.ui.util.LottieLooper
import cash.z.android.wallet.ui.util.TopAlignedSpan
import cash.z.wallet.sdk.dao.WalletTransaction
import cash.z.wallet.sdk.data.ActiveSendTransaction
@ -38,110 +38,80 @@ import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import dagger.Module
import dagger.android.ContributesAndroidInjector
import kotlinx.android.synthetic.main.activity_main_first_run.*
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.include_home_content.*
import kotlinx.android.synthetic.main.include_home_header.*
import kotlinx.coroutines.launch
import kotlin.random.Random
import kotlin.random.nextLong
import kotlin.system.measureTimeMillis
/**
* Fragment representing the home screen of the app. This is the screen most often seen by the user when launching the
* application.
*/
class HomeFragment : BaseFragment(), HomePresenter.HomeView {
class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomePresenter.HomeView {
lateinit var homePresenter: HomePresenter
lateinit var transactionAdapter: TransactionAdapter
private var viewsInitialized = false
private lateinit var homePresenter: HomePresenter
private lateinit var binding: FragmentHomeBinding
private lateinit var zcashLogoAnimation: LottieLooper
private var snackbar: Snackbar? = null
private var viewsInitialized = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewsInitialized = false
setupSharedElementTransitions()
return inflater.inflate(R.layout.fragment_home, container, false)
// setupSharedElementTransitions()
return DataBindingUtil.inflate<FragmentHomeBinding>(
inflater, R.layout.fragment_home, container, false
).let {
binding = it
it.root
}
}
private fun setupSharedElementTransitions() {
val enterTransitionSet =
TransitionInflater.from(mainActivity).inflateTransition(R.transition.transition_zec_sent).apply {
duration = 3000L
}.addListener(HomeTransitionListener())
this.sharedElementEnterTransition = enterTransitionSet
this.sharedElementReturnTransition = enterTransitionSet
TransitionInflater.from(mainActivity).inflateTransition(R.transition.transition_zec_sent).apply {
duration = 3000L
addListener(HomeTransitionListener())
this@HomeFragment.sharedElementEnterTransition = this
this@HomeFragment.sharedElementReturnTransition = this
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// setActiveTransactionsShown(false)
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)
// toggling determines visibility. hide it all.
headerFullViews.forEach { container_home_header.removeView(it) }
headerEmptyViews.forEach { container_home_header.removeView(it) }
group_empty_view_items.visibility = View.GONE
group_full_view_items.visibility = View.GONE
image_logo.setOnClickListener {
if (MainActivity.DEV_MODE) {
mainActivity.navController.navigate(R.id.nav_send_fragment)
// forceRedraw()
// toggleViews(false)
}
}
button_active_transaction_cancel.setOnClickListener {
val transaction = button_active_transaction_cancel.tag as? ActiveSendTransaction
if (transaction != null) {
homePresenter.onCancelActiveTransaction(transaction)
} else {
Toaster.short("Error: unable to find transaction to cancel!")
}
}
refresh_layout.setOnRefreshListener {
val fauxRefresh = Random.nextLong(750L..3000L)
refresh_layout.postDelayed({
refresh_layout.isRefreshing = false
}, fauxRefresh)
}
launch {
Log.e("TWIG", "deciding whether to show first run")
val extraDelay = measureTimeMillis {
setFirstRunShown(mainActivity.synchronizer.isFirstRun() || mainActivity.synchronizer.isOutOfSync())
}
Log.e("TWIG", "done deciding whether to show first run in $extraDelay ms. Was that worth it? Or should we toggle a boolean in the application class?")
}
header_active_transaction.visibility = View.GONE
refresh_layout.setProgressViewEndTarget(false, (86f * resources.displayMetrics.density).toInt())
initTemp()
init()
// launch {
// Log.e("TWIG", "deciding whether to show first run")
// val extraDelay = measureTimeMillis {
// setFirstRunShown(mainActivity.synchronizer.isFirstRun() || mainActivity.synchronizer.isOutOfSync())
// }
// Log.e("TWIG", "done deciding whether to show first run in $extraDelay ms. Was that worth it? Or should we toggle a boolean in the application class?")
// }
}
private fun setFirstRunShown(isShown: Boolean) {
container_first_run?.visibility = if (isShown) View.VISIBLE else View.GONE
mainActivity.setDrawerLocked(isShown)
sd_fab?.visibility = if (!isShown) View.VISIBLE else View.GONE
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
with(mainActivity) {
setSupportActionBar(binding.includeHeader.homeToolbar)
setupNavigation()
supportActionBar?.setTitle(R.string.destination_title_home)
}
initFab()
homePresenter = HomePresenter(this, mainActivity.synchronizer)
binding.includeContent.recyclerTransactions.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter()
addItemDecoration(AlternatingRowColorDecoration())
}
}
override fun onResume() {
super.onResume()
// val isEmpty = (recycler_transactions?.adapter?.itemCount ?: 0).let { it == 0 }
// Log.e("TWIG-t", "Resuming and isEmpty == $isEmpty")
// toggleViews(isEmpty)
launch {
homePresenter.start()
}
@ -150,28 +120,7 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
override fun onPause() {
super.onPause()
homePresenter.stop()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
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)
initFab(activity!!)
recycler_transactions.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter().also { transactionAdapter = it }
addItemDecoration(AlternatingRowColorDecoration())
}
// recycler_transactions.setOnClickListener {
// mainActivity.navController.navigate(R.id.nav_history_fragment)
// }
binding.lottieZcashBadge.cancelAnimation()
}
@ -179,70 +128,109 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
// View API
//
fun setContentViewShown(isShown: Boolean) {
with(binding.includeContent) {
groupEmptyViewItems.visibility = if (isShown) View.GONE else View.VISIBLE
groupContentViewItems.visibility = if (isShown) View.VISIBLE else View.GONE
}
toggleViews(!isShown)
}
override fun onRefresh() {
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from onRefresh") }
with(binding.includeContent.refreshLayout) {
isRefreshing = false
val fauxRefresh = Random.nextLong(750L..3000L)
postDelayed({
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onRefresh") }
}, fauxRefresh)
}
}
fun setRefreshAnimationPlaying(isPlaying: Boolean) {
Log.e("TWIG-a", "set refresh to: $isPlaying for $zcashLogoAnimation")
if (isPlaying) {
zcashLogoAnimation.start()
} else {
zcashLogoAnimation.stop()
view?.postDelayed({
zcashLogoAnimation.stop()
}, 500L)
}
}
//TODO: pull some of this logic into the presenter, particularly the part that deals with ZEC <-> USD price conversion
override fun updateBalance(old: Long, new: Long) {
//TODO: remove this kind of thing
snackbar?.dismiss()
Log.e("TWIG-t", "updating balance from $old to $new")
val zecValue = new/1e8
swapEmptyViewsForBalance(zecValue)
// TODO: animate the change in value
setZecValue(zecValue)
setUsdValue(MainActivity.USD_PER_ZEC * zecValue)
setUsdValue(SampleProperties.USD_PER_ZEC * zecValue)
onContentRefreshComplete(zecValue)
}
override fun setTransactions(transactions: List<WalletTransaction>) {
Log.e("TWIG-t", "submitList called with ${transactions.size} transactions")
transactionAdapter.submitList(transactions)
recycler_transactions.postDelayed({
recycler_transactions.smoothScrollToPosition(0)
}, 100L)
if (transactions.isNotEmpty()) setFirstRunShown(false)
with (binding.includeContent.recyclerTransactions) {
(adapter as TransactionAdapter).submitList(transactions)
postDelayed({
smoothScrollToPosition(0)
}, 100L)
if (binding.includeFirstRun.visibility == View.VISIBLE) setFirstRunShown(false)
}
}
override fun showProgress(progress: Int) {
Log.e("TWIG", "showing progress of $progress")
if(progress >= 100) {
view?.postDelayed({
onInitialLoadComplete()
}, 3000L)
} else {
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from showProgress") }
binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet_updating)
}
// snackbar.showOk(view!!, "progress: $progress")
// TODO: improve this with Lottie animation. but for now just use the empty view for downloading...
// var hasEmptyViews = group_empty_view_items.visibility == View.VISIBLE
// if(!viewsInitialized) toggleViews(true)
//
val message = if(progress >= 100) "Download complete! Processing blocks..." else "Downloading remaining blocks ($progress%)"
// text_wallet_message.text = message
if (snackbar == null && progress <= 50) {
snackbar = Snackbar.make(view!!, "$message", Snackbar.LENGTH_INDEFINITE)
.setAction("OK") {
snackbar?.dismiss()
}
snackbar?.show()
} else {
snackbar?.setText(message)
if(snackbar?.isShownOrQueued != true) snackbar?.show()
}
// val message = if(progress >= 100) "Download complete! Processing blocks..." else "Downloading remaining blocks ($progress%)"
//// text_wallet_message.text = message
//
// if (snackbar == null && progress <= 50) {
// snackbar = Snackbar.make(view!!, "$message", Snackbar.LENGTH_INDEFINITE)
// .setAction("OK") {
// snackbar?.dismiss()
// }
// snackbar?.show()
// } else {
// snackbar?.setText(message)
// if(snackbar?.isShownOrQueued != true) snackbar?.show()
// }
}
fun showOkSnack(message: String) {
if (snackbar == null) {
snackbar = Snackbar.make(view!!, "$message", Snackbar.LENGTH_INDEFINITE).setAction("OK") {
snackbar?.dismiss()
snackbar = null
}
snackbar?.show()
} else {
snackbar?.setText(message)
if (snackbar?.isShownOrQueued != true) snackbar?.show()
private fun onInitialLoadComplete() {
val isEmpty = (binding.includeContent.recyclerTransactions?.adapter?.itemCount ?: 0).let { it == 0 }
Log.e("TWIG-t", "onInitialLoadComplete and isEmpty == $isEmpty")
setContentViewShown(!isEmpty)
if (isEmpty) {
binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet)
}
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onInitialLoadComplete") }
}
override fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
if (activeTransactionMap.isEmpty()) {
setActiveTransactionsShown(false)
return
}
setActiveTransactionsShown(true)
val transactions = activeTransactionMap.entries.toTypedArray()
// primary is the last one that was inserted
val primaryEntry = transactions[transactions.size - 1]
@ -251,16 +239,17 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
}
override fun onCancelledTooLate() {
showOkSnack("Oops! It was too late to cancel!")
snackbar = snackbar.showOk(view!!, "Oops! It was too late to cancel!")
}
private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) {
setActiveTransactionsShown(true)
Log.e("TWIG", "setting transaction state to ${transactionState::class.simpleName}")
var title = "Active Transaction"
var subtitle = "Processing..."
when (transactionState) {
TransactionState.Creating -> {
header_active_transaction.visibility = View.VISIBLE
binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
title = "Preparing ${transaction.value.toZec(3)} ZEC"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress}"
setTransactionActive(transaction, true)
@ -268,48 +257,48 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
TransactionState.SendingToNetwork -> {
title = "Sending Transaction"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress}"
text_active_transaction_value.text = "${transaction.value/1000L}"
text_active_transaction_value.visibility = View.VISIBLE
button_active_transaction_cancel.visibility = View.GONE
binding.includeContent.textActiveTransactionValue.text = "${transaction.value/1000L}"
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
}
is TransactionState.Failure -> {
lottie_active_transaction.setAnimation(R.raw.lottie_send_failure)
lottie_active_transaction.playAnimation()
binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_failure)
binding.includeContent.lottieActiveTransaction.playAnimation()
title = "Failed"
subtitle = when(transactionState.failedStep) {
TransactionState.Creating -> "Failed to create transaction"
TransactionState.SendingToNetwork -> "Failed to submit transaction to the network"
else -> "Unrecoginzed error"
}
button_active_transaction_cancel.visibility = View.GONE
text_active_transaction_value.visibility = View.GONE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
binding.includeContent.textActiveTransactionValue.visibility = View.GONE
setTransactionActive(transaction, false)
setActiveTransactionsShown(false, 10000L)
}
is TransactionState.AwaitingConfirmations -> {
if (transactionState.confirmationCount < 1) {
lottie_active_transaction.setAnimation(R.raw.lottie_send_success)
lottie_active_transaction.playAnimation()
binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_success)
binding.includeContent.lottieActiveTransaction.playAnimation()
title = "ZEC Sent"
subtitle = "Today at 4:46pm"
text_active_transaction_value.text = transaction.value.toZec(3).toString()
text_active_transaction_value.visibility = View.VISIBLE
button_active_transaction_cancel.visibility = View.GONE
subtitle = "Today at 2:11pm"
binding.includeContent.textActiveTransactionValue.text = transaction.value.toZec(3).toString()
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
} else {
// play confirmation counting animation
title = "Confirmation Received"
subtitle = "Today at 2:12pm"
// take it out of the list in a bit and skip counting confirmation animation for now (i.e. one is enough)
setActiveTransactionsShown(false, 3000L)
}
}
is TransactionState.Cancelled -> {
title = text_active_transaction_title.text.toString()
subtitle = text_active_transaction_subtitle.text.toString()
title = binding.includeContent.textActiveTransactionTitle.text.toString()
subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
setTransactionActive(transaction, false)
}
}
text_active_transaction_title.text = title
text_active_transaction_subtitle.text = subtitle
}
private fun setActiveTransactionsShown(isShown: Boolean) {
header_active_transaction.visibility = if (isShown) View.VISIBLE else View.GONE
binding.includeContent.textActiveTransactionTitle.text = title
binding.includeContent.textActiveTransactionSubtitle.text = subtitle
}
@ -317,25 +306,96 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
// Private View API
//
private fun setActiveTransactionsShown(isShown: Boolean, delay: Long = 0L) {
Log.e("TWIG-a", "setActiveTransactionsShown: $isShown")
binding.includeContent.headerActiveTransaction.postDelayed({
binding.includeContent.groupActiveTransactionItems.visibility = if (isShown) View.VISIBLE else View.GONE
}, delay)
}
private fun setFirstRunShown(isShown: Boolean) {
binding.includeFirstRun.visibility = if (isShown) View.VISIBLE else View.GONE
mainActivity.setDrawerLocked(isShown)
binding.sdFab.visibility = if (!isShown) View.VISIBLE else View.GONE
binding.lottieZcashBadge.visibility = if(!isShown) View.VISIBLE else View.GONE
}
/**
* Initialize the Fab button and all its action items
*
* @param activity a helper parameter that forces this method to be called after the activity is created and not null
* General initialization called during onViewCreated. Mostly responsible for applying the default empty state of
* the view, before any data or information is known.
*/
private fun initFab(activity: Activity) {
val speedDial = sd_fab
val nav = (activity as MainActivity).navController
private fun init() {
zcashLogoAnimation = LottieLooper(binding.lottieZcashBadge, 20..47, 69)
binding.includeContent.buttonActiveTransactionCancel.setOnClickListener {
val transaction = it.tag as? ActiveSendTransaction
if (transaction != null) {
homePresenter.onCancelActiveTransaction(transaction)
} else {
Toaster.short("Error: unable to find transaction to cancel!")
}
}
binding.includeContent.refreshLayout.setProgressViewEndTarget(false, (38f * resources.displayMetrics.density).toInt())
with(binding.includeContent.refreshLayout) {
setOnRefreshListener(this@HomeFragment)
setColorSchemeColors(R.color.zcashBlack.toAppColor())
setProgressBackgroundColorSchemeColor(R.color.zcashYellow.toAppColor())
}
// hide content
setActiveTransactionsShown(false)
setContentViewShown(false)
binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet_updating)
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from init") }
}
// initialize the stuff that is temporary and needs to go ASAP
private fun initTemp() {
with(binding.includeHeader) {
headerFullViews = arrayOf(textBalanceUsd, textBalanceIncludesInfo, textBalanceZec, imageZecSymbolBalanceShadow, imageZecSymbolBalance)
headerEmptyViews = arrayOf(textBalanceZecInfo, textBalanceZecEmpty, imageZecSymbolBalanceShadowEmpty, imageZecSymbolBalanceEmpty)
headerFullViews.forEach { containerHomeHeader.removeView(it) }
headerEmptyViews.forEach { containerHomeHeader.removeView(it) }
binding.includeHeader.containerHomeHeader.visibility = View.INVISIBLE
}
// toggling determines visibility. hide it all.
binding.includeContent.groupEmptyViewItems.visibility = View.GONE
binding.includeContent.groupContentViewItems.visibility = View.GONE
}
/**
* Initialize the Fab button and all its action items. Should be called during onActivityCreated.
*/
private fun initFab() {
val speedDial = binding.sdFab
val nav = mainActivity.navController
HomeFab.values().forEach {
speedDial.addActionItem(it.createItem())
}
speedDial.setOnActionSelectedListener { item ->
HomeFab.fromId(item.id)?.destination?.apply { nav.navigate(this) }
if (item.id == R.id.fab_request) {
Toaster.short("off!")
setActiveTransactionsShown(false)
// setRefreshAnimationPlaying(false)
} else if (item.id == R.id.fab_receive) {
Toaster.short("on!")
setActiveTransactionsShown(true)
// setRefreshAnimationPlaying(true)
} else {
HomeFab.fromId(item.id)?.destination?.apply { nav.navigate(this) }
}
false
}
}
/**
* Helper for creating fablets--those little buttons that pop up when the fab is tapped.
*/
private val createItem: HomeFab.() -> SpeedDialActionItem = {
SpeedDialActionItem.Builder(id, icon)
.setFabBackgroundColor(bgColor.toAppColor())
@ -352,11 +412,13 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
val textSpan = SpannableString(valueString)
textSpan.setSpan(TopAlignedSpan(), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textSpan.setSpan(TopAlignedSpan(), valueString.length - 3, valueString.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
text_balance_usd.text = textSpan
binding.includeHeader.textBalanceUsd.text = textSpan
}
private fun setZecValue(value: Double) {
text_balance_zec.text = if(value == 0.0) "0" else String.format("%.3f",value)
binding.includeHeader.textBalanceZec.text = if(value == 0.0) "0" else String.format("%.3f",value)
// // bugfix: there is a bug in motionlayout that causes text to flicker as it is resized because the last character doesn't fit. Padding both sides with a thin space works around this bug.
// val hairSpace = "\u200A"
// val adjustedValue = "$hairSpace$valueString$hairSpace"
@ -364,34 +426,38 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
}
/**
* Called whenever the content has been refreshed on the screen. When it is time to show and hide things.
* If the balance goes to zero, the wallet is now empty so show the empty view.
* If the balance changes from zero, the wallet is no longer empty so hide the empty view.
* But don't do either of these things if the situation has not changed.
*/
private fun swapEmptyViewsForBalance(value: Double) {
private fun onContentRefreshComplete(value: Double) {
val isEmpty = value <= 0.0
// wasEmpty isn't enough info. it must be considered along with whether these views were ever initialized
val wasEmpty = group_empty_view_items.visibility == View.VISIBLE
val wasEmpty = binding.includeContent.groupEmptyViewItems.visibility == View.VISIBLE
// situation has changed when we weren't initialized but now we have a balance or emptiness has changed
val situationHasChanged = !viewsInitialized || (isEmpty != wasEmpty)
Log.e("TWIG-t", "updateEmptyViews called with value: $value initialized: $viewsInitialized isEmpty: $isEmpty wasEmpty: $wasEmpty")
if (situationHasChanged) {
Log.e("TWIG-t", "The situation has changed! toggling views!")
toggleViews(isEmpty)
setContentViewShown(!isEmpty)
if (!isEmpty) setFirstRunShown(false)
}
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onContentRefreshComplete") }
binding.includeHeader.containerHomeHeader.visibility = View.VISIBLE
}
private fun onActiveTransactionTransitionStart() {
button_active_transaction_cancel.visibility = View.INVISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.INVISIBLE
}
private fun onActiveTransactionTransitionEnd() {
// TODO: investigate if this fix is still required after getting transition animation working again
// 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
button_active_transaction_cancel.apply {
binding.includeContent.headerActiveTransaction.translationZ = 10.0f
binding.includeContent.buttonActiveTransactionCancel.apply {
postDelayed({text = "cancel"}, 50L)
visibility = View.VISIBLE
}
@ -400,38 +466,27 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
private fun setTransactionActive(transaction: ActiveTransaction, isActive: Boolean) {
// TODO: get view for transaction, mostly likely keep a sparse array of these or something
if (isActive) {
button_active_transaction_cancel.setText(R.string.cancel)
button_active_transaction_cancel.isEnabled = true
button_active_transaction_cancel.tag = transaction
header_active_transaction.animate().apply {
binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancel)
binding.includeContent.buttonActiveTransactionCancel.isEnabled = true
binding.includeContent.buttonActiveTransactionCancel.tag = transaction
binding.includeContent.headerActiveTransaction.animate().apply {
translationZ(10f)
duration = 200L
interpolator = DecelerateInterpolator()
}
} else {
button_active_transaction_cancel.setText(R.string.cancelled)
button_active_transaction_cancel.isEnabled = false
button_active_transaction_cancel.tag = null
header_active_transaction.animate().apply {
binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancelled)
binding.includeContent.buttonActiveTransactionCancel.isEnabled = false
binding.includeContent.buttonActiveTransactionCancel.tag = null
binding.includeContent.headerActiveTransaction.animate().apply {
translationZ(2f)
duration = 300L
interpolator = AccelerateInterpolator()
}
lottie_active_transaction.cancelAnimation()
binding.includeContent.lottieActiveTransaction.cancelAnimation()
}
}
inner class HomeTransitionListener : Transition.TransitionListener {
override fun onTransitionStart(transition: Transition) {
onActiveTransactionTransitionStart()
}
override fun onTransitionEnd(transition: Transition) {
onActiveTransactionTransitionEnd()
}
override fun onTransitionResume(transition: Transition){}
override fun onTransitionPause(transition: Transition){}
override fun onTransitionCancel(transition: Transition) {}
}
/**
* Defines the basic properties of each FAB button for use while initializing the FAB
@ -470,23 +525,23 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
fun fromId(id: Int): HomeFab? = values().firstOrNull { it.id == id }
}
}
// ---------------------------------------------------------------------------------------------------------------------
// TODO: Delete these test functions
// ---------------------------------------------------------------------------------------------------------------------
//
//
//
//// ---------------------------------------------------------------------------------------------------------------------
//// TODO: Delete these test functions
//// ---------------------------------------------------------------------------------------------------------------------
//
var empty = false
val delay = 50L
lateinit var headerEmptyViews: Array<View>
lateinit var headerFullViews: Array<View>
fun shrink(): Double {
return text_balance_zec.text.toString().trim().toDouble() - Random.nextDouble(5.0)
return binding.includeHeader.textBalanceZec.text.toString().trim().toDouble() - Random.nextDouble(5.0)
}
fun grow(): Double {
return text_balance_zec.text.toString().trim().toDouble() + Random.nextDouble(5.0)
return binding.includeHeader.textBalanceZec.text.toString().trim().toDouble() + Random.nextDouble(5.0)
}
fun reduceValue() {
shrink().let {
@ -512,36 +567,70 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
}
fun forceRedraw() {
view?.postDelayed({
container_home_header.progress = container_home_header.progress - 0.1f
binding.includeHeader.containerHomeHeader.progress = binding.includeHeader.containerHomeHeader.progress - 0.1f
}, delay * 2)
}
internal fun toggle(isEmpty: Boolean) {
toggleValues(isEmpty)
}
// TODO: get rid of all of this and consider two different fragments for the header, instead
internal fun toggleViews(isEmpty: Boolean) {
Log.e("TWIG-t", "toggling views to isEmpty == $isEmpty")
var action: () -> Unit
if (isEmpty) {
action = {
group_empty_view_items.visibility = View.VISIBLE
group_full_view_items.visibility = View.GONE
headerFullViews.forEach { container_home_header.removeView(it) }
binding.includeContent.groupEmptyViewItems.visibility = View.VISIBLE
binding.includeContent.groupContentViewItems.visibility = View.GONE
headerFullViews.forEach { binding.includeHeader.containerHomeHeader.removeView(it) }
headerEmptyViews.forEach {
tryIgnore {
container_home_header.addView(it)
binding.includeHeader.containerHomeHeader.addView(it)
}
}
}
} else {
action = {
group_empty_view_items.visibility = View.GONE
group_full_view_items.visibility = View.VISIBLE
headerEmptyViews.forEach { container_home_header.removeView(it) }
binding.includeContent.groupEmptyViewItems.visibility = View.GONE
binding.includeContent.groupContentViewItems.visibility = View.VISIBLE
headerEmptyViews.forEach { binding.includeHeader.containerHomeHeader.removeView(it) }
headerFullViews.forEach {
tryIgnore {
container_home_header.addView(it)
binding.includeHeader.containerHomeHeader.addView(it)
}
}
}
}
view?.postDelayed({
binding.includeHeader.containerHomeHeader.visibility = View.VISIBLE
action()
viewsInitialized = true
}, delay)
// TODO: the motion layout does not begin in the right state for some reason. Debug this later.
view?.postDelayed(::forceRedraw, delay * 2)
}
// TODO: get rid of all of this and consider two different fragments for the header, instead
internal fun toggleViews2(isEmpty: Boolean) {
var action: () -> Unit
if (isEmpty) {
action = {
// group_empty_view_items.visibility = View.VISIBLE
// group_full_view_items.visibility = View.GONE
headerFullViews.forEach { binding.includeHeader.containerHomeHeader.removeView(it) }
headerEmptyViews.forEach {
tryIgnore {
binding.includeHeader.containerHomeHeader.addView(it)
}
}
}
} else {
action = {
// group_empty_view_items.visibility = View.GONE
// group_full_view_items.visibility = View.VISIBLE
headerEmptyViews.forEach { binding.includeHeader.containerHomeHeader.removeView(it) }
headerFullViews.forEach {
tryIgnore {
binding.includeHeader.containerHomeHeader.addView(it)
}
}
}
@ -562,10 +651,25 @@ class HomeFragment : BaseFragment(), HomePresenter.HomeView {
increaseValue(Random.nextDouble(20.0, 100.0))
}
}
inner class HomeTransitionListener : Transition.TransitionListener {
override fun onTransitionStart(transition: Transition) {
}
override fun onTransitionEnd(transition: Transition) {
}
override fun onTransitionResume(transition: Transition) {}
override fun onTransitionPause(transition: Transition) {}
override fun onTransitionCancel(transition: Transition) {}
}
}
@Module
abstract class HomeFragmentModule {
@ContributesAndroidInjector
abstract fun contributeHomeFragment(): HomeFragment
}
}

View File

@ -0,0 +1,22 @@
package cash.z.android.wallet.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.IncludeHomeHeaderBinding
class HomeHeaderEmptyFragment : Fragment() {
private lateinit var binding: IncludeHomeHeaderBinding
override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup?, savedInstanceState: Bundle?): View? {
return DataBindingUtil
.inflate<IncludeHomeHeaderBinding>(inflater, R.layout.include_home_header, parent, false).let {
binding = it
it.root
}
}
}

View File

@ -9,7 +9,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService
import androidx.core.text.toSpannable
import androidx.databinding.DataBindingUtil
@ -20,11 +19,12 @@ import cash.z.android.wallet.databinding.FragmentSendBinding
import cash.z.android.wallet.extention.afterTextChanged
import cash.z.android.wallet.extention.toAppColor
import cash.z.android.wallet.extention.tryIgnore
import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.sample.SampleProperties.DEV_MODE
import cash.z.android.wallet.ui.activity.MainActivity
import cash.z.android.wallet.ui.presenter.SendPresenter
import dagger.Module
import dagger.android.ContributesAndroidInjector
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.launch
import java.text.DecimalFormat
@ -55,7 +55,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
//
// this.allowReturnTransitionOverlap = false
// allowEnterTransitionOverlap = false
0
return DataBindingUtil.inflate<FragmentSendBinding>(
inflater, R.layout.fragment_send, container, false
).let {
@ -85,9 +85,9 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
tryIgnore {
val value = binding.textValueHeader.text.toString().toDouble()
binding.textValueSubheader.text = if (zecSelected) {
usdFormatter.format(value * MainActivity.USD_PER_ZEC)
usdFormatter.format(value * SampleProperties.USD_PER_ZEC)
} else {
zecFormatter.format(value / MainActivity.USD_PER_ZEC)
zecFormatter.format(value / SampleProperties.USD_PER_ZEC)
}
}
}
@ -107,7 +107,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
hideSendDialog()
}
binding.dialogSubmitButton.setOnClickListener {
if (MainActivity.DEV_MODE) submit() else onSendZec()
if (DEV_MODE) submit() else onSendZec()
}
}
@ -122,7 +122,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
launch {
sendPresenter.start()
}
if(MainActivity.DEV_MODE) showSendDialog()
if(DEV_MODE) showSendDialog()
}
override fun onPause() {
@ -131,13 +131,19 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
}
override fun submit() {
mainActivity.navController.navigate(R.id.nav_home_fragment,
null,
null,
FragmentNavigatorExtras(binding.dialogTextTitle to "transition_active_transaction_title"))
submitNoAnimations()
}
fun submitOld() {
private fun submitNoAnimations() {
mainActivity.navController.navigate(
R.id.nav_home_fragment,
null,
null,
FragmentNavigatorExtras(binding.dialogTextTitle to "transition_active_transaction_title")
)
}
fun submitWithSharedElements() {
var extras = with(binding) {
listOf(dialogSendBackground, dialogSendContents, dialogTextTitle, dialogTextAddress)
.map{ it to it.transitionName }
@ -171,7 +177,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView {
override fun updateBalance(old: Long, new: Long) {
val zecBalance = new / 100000000.0
val usdBalance = zecBalance * MainActivity.USD_PER_ZEC
val usdBalance = zecBalance * SampleProperties.USD_PER_ZEC
val availableZecFormatter = DecimalFormat("#.########")
// TODO: use a formatted string resource here
val availableTextSpan = "${availableZecFormatter.format(zecBalance)} ZEC Available".toSpannable()

View File

@ -0,0 +1,88 @@
package cash.z.android.wallet.ui.util
import android.animation.Animator
import cash.z.android.wallet.extention.Toaster
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieDrawable
/**
* Utility to help with looping a lottie animation over a particular range. It will start the animation and play it up
* to the end of the range and then set it to loop over the range and, once stopped, it will proceed from the current
* frame to the end of the animation. Visually: BEGIN...LOOP...LOOP...LOOP...END
*/
class LottieLooper(private val lottie: LottieAnimationView, private val loopRange: IntRange, private val lastFrame: Int = Int.MAX_VALUE) :
Animator.AnimatorListener {
var isPlaying = false
fun start() {
if (isPlaying) return
with(lottie) {
setMinAndMaxFrame(1, loopRange.last)
repeatCount = 0
addAnimatorListener(this@LottieLooper)
playAnimation()
}
isPlaying = true
}
fun stop() {
with(lottie) {
setMinAndMaxFrame(lottie.frame, lastFrame)
repeatCount = 0
// we don't want to just cancel the animation. We want it to finish it's final frames but the moment it is
// done, we need it to freeze on that final frame and then die
addAnimatorListener(LottieAssassin())
}
isPlaying = false
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator?) {
with(lottie) {
removeAllAnimatorListeners()
setMinAndMaxFrame(loopRange.first, loopRange.last)
repeatCount = LottieDrawable.INFINITE
playAnimation()
}
}
override fun onAnimationCancel(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
/** I have one job: kill lottie */
inner class LottieAssassin : Animator.AnimatorListener {
override fun onAnimationRepeat(animation: Animator?) {
finishingMove()
}
override fun onAnimationEnd(animation: Animator?) {
finishingMove()
}
override fun onAnimationCancel(animation: Animator?) {
finishingMove()
}
override fun onAnimationStart(animation: Animator?) {
finishingMove()
}
/** Agressively force it to freeze on the lastframe */
private fun finishingMove() {
lottie.pauseAnimation()
lottie.setMinAndMaxFrame(lastFrame, lastFrame)
lottie.progress = 1.0f
// wait around a bit to see if there's any movement, then quietly make my getaway
lottie.postDelayed({
lottie.removeAnimatorListener(this)
lottie.setMinAndMaxFrame(1, lastFrame)
}, 500L)
}
}
}

View File

@ -1,42 +1,53 @@
<?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"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/home_app_bar"
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="@dimen/home_app_bar_expanded_height"
android:theme="@style/ZcashTheme.AppBarOverlay">
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<include layout="@layout/include_home_header" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/home_app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/home_app_bar_expanded_height"
android:theme="@style/ZcashTheme.AppBarOverlay">
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/include_header"
layout="@layout/include_home_header" />
<include layout="@layout/include_home_content" />
</com.google.android.material.appbar.AppBarLayout>
<!-- FAB -->
<com.leinardi.android.speeddial.SpeedDialView
android:id="@+id/sd_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:sdMainFabClosedBackgroundColor="@color/fab_closed_color"
app:sdMainFabClosedSrc="@drawable/ic_add_white_24dp"
app:sdMainFabOpenedBackgroundColor="@color/fab_open_color" />
<include
android:id="@+id/include_content"
layout="@layout/include_home_content" />
<!-- Zcash badge -->
<ImageView
android:id="@+id/image_logo"
android:layout_width="50dp"
android:layout_height="50dp"
android:elevation="6dp"
app:layout_anchor="@id/home_app_bar"
app:layout_anchorGravity="bottom|center"
app:srcCompat="@drawable/ic_zcashlogo_badge" />
<!-- FAB -->
<com.leinardi.android.speeddial.SpeedDialView
android:id="@+id/sd_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:sdMainFabClosedBackgroundColor="@color/fab_closed_color"
app:sdMainFabClosedSrc="@drawable/ic_add_white_24dp"
app:sdMainFabOpenedBackgroundColor="@color/fab_open_color" />
<include layout="@layout/activity_main_first_run"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<!-- Zcash badge - refresh animation -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_zcash_badge"
android:layout_width="50dp"
android:layout_height="50dp"
android:elevation="6dp"
app:layout_anchor="@id/home_app_bar"
app:layout_anchorGravity="bottom|center"
app:lottie_autoPlay="false"
app:lottie_loop="false"
app:lottie_rawRes="@raw/lottie_zcash_badge_refresh_whitebg" />
<include
android:id="@+id/include_first_run"
layout="@layout/activity_main_first_run" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -0,0 +1,44 @@
<?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.
-->
<layout 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">
<cash.z.android.wallet.ui.view.CollapsingMotionToolbar
android:id="@+id/fragment_container_home_header_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:minHeight="?attr/actionBarSize"
app:layoutDescription="@xml/scene_fragment_home_header_empty"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
tools:showIn="@layout/fragment_home">
<!-- balance: empty -->
<TextView
android:id="@+id/text_balance_zec_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
android:text="0"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
</cash.z.android.wallet.ui.view.CollapsingMotionToolbar>
</layout>

View File

@ -0,0 +1,45 @@
<?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.
-->
<layout 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">
<cash.z.android.wallet.ui.view.CollapsingMotionToolbar
android:id="@+id/fragment_container_home_header_full"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:minHeight="?attr/actionBarSize"
app:layoutDescription="@xml/scene_fragment_home_header_full"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
tools:showIn="@layout/fragment_home">
<!-- balance -->
<TextView
android:id="@+id/text_balance_zec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
tools:text="35.021"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
</cash.z.android.wallet.ui.view.CollapsingMotionToolbar>
</layout>

View File

@ -1,181 +1,206 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<layout 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/scrollable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/fragment_home_background"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
xmlns:tools="http://schemas.android.com/tools">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/fragment_home_background"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="16dp"
android:paddingTop="30dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:transitionName="@string/transition_active_transaction_background">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- Active Transaction - primary -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/header_active_transaction"
android:id="@+id/content_home"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@drawable/background_rounded_corners_slight"
android:clipToPadding="false"
android:layout_height="match_parent"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingTop="16dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:paddingTop="30dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:transitionName="@string/transition_active_transaction_card"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
android:transitionName="@string/transition_active_transaction_background">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_active_transaction"
android:layout_width="36dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
<!-- Label: Current Activity -->
<TextView
android:id="@+id/text_active_transaction_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/home_current_transaction_label"
android:textColor="@color/text_dark"
android:textSize="@dimen/text_size_body_2"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="false"
app:lottie_rawRes="@raw/lottie_send_common" />
tools:visibility="visible" />
<!-- Active Transaction - primary -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/header_active_transaction"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginTop="12dp"
android:background="@drawable/background_rounded_corners_slight"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingTop="16dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:paddingBottom="16dp"
android:transitionName="@string/transition_active_transaction_card"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_active_transaction_header"
tools:visibility="visible">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottie_active_transaction"
android:layout_width="36dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="false"
app:lottie_rawRes="@raw/lottie_send_common" />
<TextView
android:id="@+id/text_active_transaction_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:textSize="@dimen/text_size_body_1"
android:textStyle="bold"
android:transitionName="@string/transition_active_transaction_title"
app:layout_constraintBottom_toTopOf="@id/text_active_transaction_subtitle"
app:layout_constraintStart_toEndOf="@id/lottie_active_transaction"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Preparing 1.01 ZEC" />
<TextView
android:id="@+id/text_active_transaction_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="to zsapling...123456789"
android:textSize="@dimen/text_size_caption"
android:transitionName="@string/transition_active_transaction_address"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/text_active_transaction_title"
app:layout_constraintTop_toBottomOf="@id/text_active_transaction_title" />
<TextView
android:id="@+id/text_active_transaction_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:textColor="@color/text_dark_dimmed"
android:textSize="@dimen/text_size_h5"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_active_transaction_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:text="cancel"
android:textColor="@color/selector_red_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Label: Past Activity -->
<TextView
android:id="@+id/text_active_transaction_title"
android:id="@+id/text_transaction_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:text="Preparing 1.01 ZEC"
android:textSize="@dimen/text_size_body_1"
android:layout_marginTop="16dp"
android:paddingBottom="12dp"
android:text="@string/home_past_transaction_label"
android:textColor="@color/text_dark"
android:textSize="@dimen/text_size_body_2"
android:textStyle="bold"
android:transitionName="@string/transition_active_transaction_title"
app:layout_constraintBottom_toTopOf="@id/text_active_transaction_subtitle"
app:layout_constraintStart_toEndOf="@id/lottie_active_transaction"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_active_transaction"
app:layout_goneMarginTop="0dp" />
<!-- Transactions -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_transactions"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingBottom="72dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_transaction_header"
tools:itemCount="15"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_transaction"
tools:orientation="vertical" />
<!-- Empty: image -->
<ImageView
android:id="@+id/image_empty_wallet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
app:layout_constraintVertical_bias="0.281966"
app:srcCompat="@drawable/ic_emptywallet" />
<!-- Empty: message -->
<TextView
android:id="@+id/text_active_transaction_subtitle"
android:id="@+id/text_empty_wallet_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="to zsapling...123456789"
android:textSize="@dimen/text_size_caption"
android:transitionName="@string/transition_active_transaction_address"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/text_active_transaction_title"
app:layout_constraintTop_toBottomOf="@id/text_active_transaction_title" />
<TextView
android:id="@+id/text_active_transaction_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:textColor="@color/text_dark_dimmed"
android:textSize="@dimen/text_size_h5"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="8dp"
android:gravity="center"
android:padding="16dp"
android:text="@string/home_empty_wallet"
android:textColor="#AAAAAA"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_empty_wallet" />
<Button
android:id="@+id/button_active_transaction_cancel"
<!-- -->
<!-- Groups -->
<!-- -->
<androidx.constraintlayout.widget.Group
android:id="@+id/group_active_transaction_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:text="cancel"
android:textColor="@color/selector_red_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:constraint_referenced_ids="text_active_transaction_header,header_active_transaction" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_content_view_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="text_transaction_header,recycler_transactions" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_empty_view_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="image_empty_wallet,text_empty_wallet_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Label: Past Activity -->
<TextView
android:id="@+id/text_transaction_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingBottom="16dp"
android:text="Past Activity"
android:textColor="@color/text_dark"
android:textSize="@dimen/text_size_body_2"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_active_transaction" />
<!-- Transactions -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_transactions"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingBottom="72dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_transaction_header"
tools:itemCount="15"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_transaction"
tools:orientation="vertical" />
<!-- Empty: image -->
<ImageView
android:id="@+id/image_empty_wallet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.281966"
app:srcCompat="@drawable/ic_emptywallet" />
<!-- Empty: message -->
<TextView
android:id="@+id/text_wallet_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:padding="16dp"
android:text="@string/home_empty_wallet"
android:textColor="#AAAAAA"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_empty_wallet" />
<!-- -->
<!-- Groups -->
<!-- -->
<androidx.constraintlayout.widget.Group
android:id="@+id/group_full_view_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="text_transaction_header,recycler_transactions" />
<androidx.constraintlayout.widget.Group
android:id="@+id/group_empty_view_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="image_empty_wallet,text_wallet_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.core.widget.NestedScrollView>
</layout>

View File

@ -12,117 +12,119 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<cash.z.android.wallet.ui.view.CollapsingMotionToolbar xmlns:android="http://schemas.android.com/apk/res/android"
<layout 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_home_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:minHeight="?attr/actionBarSize"
app:layoutDescription="@xml/scene_fragment_home_header"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
tools:showIn="@layout/fragment_home">
xmlns:tools="http://schemas.android.com/tools">
<Space
android:id="@+id/space_left_icon"
android:layout_width="50dp"
android:layout_height="?attr/actionBarSize"/>
<!-- Toolbar -->
<androidx.appcompat.widget.Toolbar
android:id="@+id/home_toolbar"
<cash.z.android.wallet.ui.view.CollapsingMotionToolbar
android:id="@+id/container_home_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:popupTheme="@style/ZcashTheme.PopupOverlay" />
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:minHeight="?attr/actionBarSize"
app:layoutDescription="@xml/scene_fragment_home_header"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
tools:showIn="@layout/fragment_home">
<!-- balance -->
<TextView
android:id="@+id/text_balance_zec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
tools:text="35.021"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
<Space
android:id="@+id/space_left_icon"
android:layout_width="50dp"
android:layout_height="?attr/actionBarSize" />
<!-- balance: empty -->
<TextView
android:id="@+id/text_balance_zec_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
android:text="0"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
<!-- Toolbar -->
<androidx.appcompat.widget.Toolbar
android:id="@+id/home_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:popupTheme="@style/ZcashTheme.PopupOverlay" />
<!-- Zec symbol: shadow -->
<ImageView
android:id="@+id/image_zec_symbol_balance_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#B3000000"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- balance -->
<TextView
android:id="@+id/text_balance_zec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
tools:text="35.021"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
<!-- Zec symbol -->
<ImageView
android:id="@+id/image_zec_symbol_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- balance: empty -->
<TextView
android:id="@+id/text_balance_zec_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="4dp"
android:shadowColor="@color/text_shadow"
android:shadowDx="0"
android:shadowDy="8"
android:shadowRadius="24"
android:text="0"
android:textColor="@color/zcashWhite"
android:textSize="60dp" />
<!-- Zec symbol empty: shadow -->
<ImageView
android:id="@+id/image_zec_symbol_balance_shadow_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#B3000000"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- Zec symbol: shadow -->
<ImageView
android:id="@+id/image_zec_symbol_balance_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#B3000000"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- Zec symbol empty -->
<ImageView
android:id="@+id/image_zec_symbol_balance_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- Zec symbol -->
<ImageView
android:id="@+id/image_zec_symbol_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- Balance includes active transactions -->
<TextView
android:id="@+id/text_balance_includes_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/text_light_dimmed"
android:textSize="@dimen/text_size_caption" />
<!-- Zec symbol empty: shadow -->
<ImageView
android:id="@+id/image_zec_symbol_balance_shadow_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="#B3000000"
app:srcCompat="@drawable/ic_zec_symbol" />
<TextView
android:id="@+id/text_balance_usd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
tools:text="$5,459.32"
android:textColor="@color/text_light_dimmed"
android:textSize="24dp" />
<!-- Zec symbol empty -->
<ImageView
android:id="@+id/image_zec_symbol_balance_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_zec_symbol" />
<!-- Balance includes active transactions -->
<TextView
android:id="@+id/text_balance_includes_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/text_light_dimmed"
android:textSize="@dimen/text_size_caption" />
<TextView
android:id="@+id/text_balance_usd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
tools:text="$5,459.32"
android:textColor="@color/text_light_dimmed"
android:textSize="24dp" />
<TextView
android:id="@+id/text_balance_zec_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_zec_symbol"
android:drawableLeft="@drawable/ic_zec_symbol"
android:drawablePadding="6dp"
android:text="is a currency symbol for ZEC"
android:textColor="@color/zcashWhite"
android:textSize="16dp"
/>
<TextView
android:id="@+id/text_balance_zec_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_zec_symbol"
android:drawableLeft="@drawable/ic_zec_symbol"
android:drawablePadding="6dp"
android:text="is a currency symbol for ZEC"
android:textColor="@color/zcashWhite"
android:textSize="16dp" />
</cash.z.android.wallet.ui.view.CollapsingMotionToolbar>
</cash.z.android.wallet.ui.view.CollapsingMotionToolbar>
</layout>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:id="@+id/content_home_header"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</layout>

File diff suppressed because one or more lines are too long

View File

@ -33,6 +33,7 @@
<color name="zcashBlack">#00000000</color>
<color name="zcashPrimaryMedium">#136E6E</color>
<color name="zcashRed">#B00016</color>
<color name="zcashYellow">#f4b728</color>
<!-- -->
<!-- named colors -->

View File

@ -10,6 +10,7 @@
<!-- General -->
<string name="cancel">cancel</string>
<string name="cancelled">cancelled</string>
<string name="ok_allcaps">OK</string>
<!-- Destinations -->
<string name="destination_title_home" />
@ -36,10 +37,21 @@
<string name="transition_active_transaction_address">transition_active_transaction_address</string>
<string name="transition_active_transaction_card">transition_active_transaction_card</string>
<!-- -->
<!-- Screen copy -->
<string name="receive_address_title">Your Zcash shielded address</string>
<!-- -->
<!-- Home -->
<string name="home_empty_wallet">Your wallet is empty.</string>
<string name="home_empty_wallet_updating">Updating your wallet...</string>
<string name="home_empty_wallet_collapse">Future transactions will show up here.</string>
<string name="home_current_transaction_label">Current Activity</string>
<string name="home_past_transaction_label">Past Activity</string>
<!-- Receive -->
<string name="receive_address_title">Your Zcash shielded address</string>
<!-- Send -->
<string name="send_hint_input_zcash_address">Enter a Zcash address</string>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start">
<ConstraintSet android:id="@id/start">
<Constraint
android:id="@id/text_balance_zec_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintVertical_bias="0.36"/>
</ConstraintSet>
<ConstraintSet android:id="@id/end">
<Constraint
android:id="@id/text_balance_zec_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha='0.0'
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintVertical_bias="0.36"/>
</ConstraintSet>
<KeyFrameSet>
<KeyAttribute
android:alpha="0.0"
motion:framePosition="10"
motion:target="@id/text_balance_zec_empty" />
</KeyFrameSet>
</Transition>
</MotionScene>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start">
<ConstraintSet android:id="@id/start">
<Constraint
android:id="@id/text_balance_zec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintVertical_bias="0.36">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue="60.0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@id/end">
<Constraint
android:id="@id/text_balance_zec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/space_left_icon"
motion:layout_constraintStart_toEndOf="@id/space_left_icon"
motion:layout_constraintTop_toTopOf="@id/space_left_icon">
<CustomAttribute
motion:attributeName="textSize"
motion:customFloatValue="24.0" />
</Constraint>
</ConstraintSet>
<KeyFrameSet>
<KeyPosition
motion:curveFit="spline"
motion:framePosition="80"
motion:keyPositionType="deltaRelative"
motion:pathMotionArc="startVertical"
motion:percentX="0.36"
motion:target="@id/text_balance_zec" />
</KeyFrameSet>
</Transition>
</MotionScene>