checkpoint: mock is nearly feature-complete

This commit is contained in:
Kevin Gorham 2019-02-19 08:22:45 -05:00 committed by Kevin Gorham
parent 068d17feda
commit b215c85915
69 changed files with 1095 additions and 247 deletions

View File

@ -3,6 +3,8 @@ package cash.z.android.wallet
import android.content.Context
import androidx.multidex.MultiDex
import cash.z.android.wallet.di.component.DaggerApplicationComponent
import cash.z.wallet.sdk.data.TroubleshootingTwig
import cash.z.wallet.sdk.data.Twig
import com.facebook.stetho.Stetho
import dagger.android.AndroidInjector
import dagger.android.DaggerApplication
@ -14,6 +16,7 @@ class ZcashWalletApplication : DaggerApplication() {
instance = this
super.onCreate()
Stetho.initializeWithDefaults(this)
Twig.plant(TroubleshootingTwig())
}
/**

View File

@ -26,12 +26,15 @@ import javax.inject.Singleton
AboutFragmentModule::class,
HistoryFragmentModule::class,
HomeFragmentModule::class,
ImportFragmentModule::class,
WelcomeFragmentModule::class,
ReceiveFragmentModule::class,
RequestFragmentModule::class,
SendFragmentModule::class,
ScanFragmentModule::class,
SettingsFragmentModule::class
SettingsFragmentModule::class,
WelcomeFragmentModule::class,
FirstrunFragmentModule::class,
SyncFragmentModule::class
]
)
interface ApplicationComponent : AndroidInjector<ZcashWalletApplication> {

View File

@ -6,4 +6,8 @@ internal inline fun tryIgnore(block: () -> Unit) {
internal inline fun <T> tryNull(block: () -> T): T? {
return try { block() } catch(ignored: Throwable) { null }
}
internal inline fun String.truncate(): String {
return "${substring(0..4)}...${substring(length-5, length)}"
}

View File

@ -1,14 +1,23 @@
package cash.z.android.wallet.ui.activity
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.view.inputmethod.InputMethodManager.HIDE_NOT_ALWAYS
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.core.app.ActivityCompat
import androidx.core.content.getSystemService
import androidx.core.view.GravityCompat
import androidx.core.view.doOnLayout
import androidx.databinding.DataBindingUtil
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.NavController
import androidx.navigation.NavDestination
@ -20,15 +29,13 @@ 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.databinding.ActivityMainBinding
import dagger.Module
import dagger.android.ContributesAndroidInjector
import dagger.android.support.DaggerAppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.nav_header_main.*
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.channels.ReceiveChannel
@ -41,34 +48,44 @@ class MainActivity : BaseActivity() {
@Inject
lateinit var synchronizer: Synchronizer
lateinit var binding: ActivityMainBinding
// used to manage the drawer and drawerToggle interactions
private lateinit var appBarConfiguration: AppBarConfiguration
lateinit var navController: NavController
private val multiStartNavigationUi = MultiStartNavigationUI(listOf(
R.id.nav_home_fragment,
R.id.nav_welcome_fragment
))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
initAppBar()
synchronizer.start(this)
}
private fun initAppBar() {
setSupportActionBar(findViewById(R.id.main_toolbar))
// supportActionBar?.setDisplayHomeAsUpEnabled(false)
setupNavigation()
supportActionBar?.setTitle("main title")
}
override fun onDestroy() {
super.onDestroy()
synchronizer.stop()
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onResume() {
super.onResume()
// if(DEV_MODE) navController.navigate(R.id.nav_send_fragment)
}
/**
* Let the navController override the default behavior when the drawer icon or back arrow are clicked. This
* automatically takes care of the drawer toggle behavior. Note that without overriding this method, the up/drawer
@ -79,30 +96,39 @@ class MainActivity : BaseActivity() {
}
fun setDrawerLocked(isLocked: Boolean) {
drawer_layout.setDrawerLockMode(if (isLocked) DrawerLayout.LOCK_MODE_LOCKED_CLOSED else DrawerLayout.LOCK_MODE_UNLOCKED)
binding.drawerLayout.setDrawerLockMode(if (isLocked) DrawerLayout.LOCK_MODE_LOCKED_CLOSED else DrawerLayout.LOCK_MODE_UNLOCKED)
}
fun openDrawer(view: View) {
binding.drawerLayout.openDrawer(GravityCompat.START)
}
fun setToolbarShown(isShown: Boolean) {
binding.mainAppBar.visibility = if (isShown) View.VISIBLE else View.INVISIBLE
}
fun setupNavigation() {
// create and setup the navController and appbarConfiguration
navController = Navigation.findNavController(this, R.id.nav_host_fragment).also { n ->
appBarConfiguration = AppBarConfiguration(n.graph, drawer_layout).also { a ->
nav_view.setupWithNavController(n)
setupActionBarWithNavController(n, a)
appBarConfiguration = AppBarConfiguration(n.graph, binding.drawerLayout).also { a ->
binding.navView.setupWithNavController(n)
multiStartNavigationUi.setupActionBarWithNavController(this, n, binding.drawerLayout)
}
}
navController.addOnNavigatedListener { _, _ ->
// hide the keyboard anytime we change destinations
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(nav_view.windowToken, HIDE_NOT_ALWAYS)
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(binding.navView.windowToken, HIDE_NOT_ALWAYS)
}
// remove icon tint so that our colored nav icons show through
nav_view.itemIconTintList = null
binding.navView.itemIconTintList = null
nav_view.doOnLayout {
text_nav_header_subtitle.text = "Version ${BuildConfig.VERSION_NAME}"
binding.navView.doOnLayout {
binding.navView.findViewById<TextView>(R.id.text_nav_header_subtitle).text = "Version ${BuildConfig.VERSION_NAME}"
}
}
companion object {
init {
// Enable vector drawable magic
@ -115,4 +141,82 @@ class MainActivity : BaseActivity() {
abstract class MainActivityModule {
@ContributesAndroidInjector
abstract fun contributeMainActivity(): MainActivity
}
class MultiStartNavigationUI(private val startDestinations: List<Int>) {
fun setupActionBarWithNavController(activity: AppCompatActivity, navController: NavController,
drawerLayout: DrawerLayout?) {
navController.addOnNavigatedListener(ActionBarOnNavigatedListener(
activity, startDestinations, drawerLayout))
}
fun navigateUp(drawerLayout: DrawerLayout?, navController: NavController): Boolean {
if (drawerLayout != null && startDestinations.contains(navController.currentDestination?.id)) {
drawerLayout.openDrawer(GravityCompat.START)
return true
} else {
return navController.navigateUp()
}
}
fun onBackPressed(activity: AppCompatActivity,
navController: NavController): Boolean {
if (startDestinations.contains(navController.currentDestination?.id)) {
ActivityCompat.finishAfterTransition(activity)
return true
}
return false
}
private class ActionBarOnNavigatedListener(
private val mActivity: AppCompatActivity,
private val startDestinations: List<Int>,
private val mDrawerLayout: DrawerLayout?
) : NavController.OnNavigatedListener {
private var mArrowDrawable: DrawerArrowDrawable? = null
private var mAnimator: ValueAnimator? = null
override fun onNavigated(controller: NavController, destination: NavDestination) {
val actionBar = mActivity.supportActionBar
val title = destination.label
if (!title.isNullOrEmpty()) {
actionBar?.title = title
}
val isStartDestination = startDestinations.contains(destination.id)
actionBar?.setDisplayHomeAsUpEnabled(this.mDrawerLayout != null || !isStartDestination)
setActionBarUpIndicator(mDrawerLayout != null && isStartDestination)
}
private fun setActionBarUpIndicator(showAsDrawerIndicator: Boolean) {
val delegate = mActivity.drawerToggleDelegate
var animate = true
if (mArrowDrawable == null) {
mArrowDrawable = DrawerArrowDrawable(delegate!!.actionBarThemedContext)
delegate.setActionBarUpIndicator(mArrowDrawable, 0)
animate = false
}
mArrowDrawable?.let {
val endValue = if (showAsDrawerIndicator) 0.0f else 1.0f
if (animate) {
val startValue = it.progress
mAnimator?.cancel()
@SuppressLint("ObjectAnimatorBinding")
mAnimator = ObjectAnimator.ofFloat(it, "progress", startValue, endValue)
mAnimator?.start()
} else {
it.progress = endValue
}
}
}
}
}

View File

@ -0,0 +1,94 @@
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.core.view.doOnPreDraw
import androidx.databinding.DataBindingUtil
import androidx.transition.Transition
import androidx.transition.TransitionInflater
import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentFirstrunBinding
import dagger.Module
import dagger.android.ContributesAndroidInjector
class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.TransitionListener {
private lateinit var binding: FragmentFirstrunBinding
//
// Lifecycle
//
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setupSharedElementTransitions()
return DataBindingUtil.inflate<FragmentFirstrunBinding>(
inflater, R.layout.fragment_firstrun, container, false
).let {
binding = it
it.root
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
postponeEnterTransition()
binding.buttonNext.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_sync_fragment)
}
binding.buttonNext.alpha = 0f
binding.textProgressFirstrun.alpha = 0f
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(view?.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
}
}
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(false)
}
private fun setupSharedElementTransitions() {
TransitionInflater.from(mainActivity).inflateTransition(R.transition.transition_zec_sent).apply {
duration = 250L
addListener(this@FirstrunFragment)
this@FirstrunFragment.sharedElementEnterTransition = this
this@FirstrunFragment.sharedElementReturnTransition = this
}
}
override fun onProgressComplete() {
super.onProgressComplete()
binding.textProgressFirstrun.visibility = View.GONE
}
override fun onTransitionEnd(transition: Transition) {
binding.buttonNext.animate().apply {
duration = 300L
}.alpha(1.0f)
binding.textProgressFirstrun.animate().apply {
duration = 300L
}.alpha(1.0f)
}
override fun onTransitionResume(transition: Transition) {}
override fun onTransitionPause(transition: Transition) {}
override fun onTransitionCancel(transition: Transition) {}
override fun onTransitionStart(transition: Transition) {}
}
@Module
abstract class FirstrunFragmentModule {
@ContributesAndroidInjector
abstract fun contributeFirstrunFragment(): FirstrunFragment
}

View File

@ -30,15 +30,6 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.let { mainActivity ->
mainActivity.setSupportActionBar(view.findViewById(R.id.toolbar))
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
mainActivity.supportActionBar?.setTitle(R.string.destination_title_history)
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
historyPresenter = HistoryPresenter(this, mainActivity.synchronizer)

View File

@ -26,6 +26,7 @@ import cash.z.android.wallet.sample.SampleProperties
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.AnimatorCompleteListener
import cash.z.android.wallet.ui.util.LottieLooper
import cash.z.android.wallet.ui.util.TopAlignedSpan
import cash.z.wallet.sdk.dao.WalletTransaction
@ -93,11 +94,8 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
with(mainActivity) {
setSupportActionBar(binding.includeHeader.homeToolbar)
setupNavigation()
supportActionBar?.setTitle(R.string.destination_title_home)
}
mainActivity.setToolbarShown(false)
mainActivity.setDrawerLocked(false)
initFab()
homePresenter = HomePresenter(this, mainActivity.synchronizer)
@ -162,9 +160,6 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
//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) {
val zecValue = new.convertZatoshiToZec()
@ -176,7 +171,9 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
override fun setTransactions(transactions: List<WalletTransaction>) {
with (binding.includeContent.recyclerTransactions) {
(adapter as TransactionAdapter).submitList(transactions)
(adapter as TransactionAdapter).submitList(transactions.sortedByDescending {
it.timeInSeconds
})
postDelayed({
smoothScrollToPosition(0)
}, 100L)
@ -242,23 +239,27 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
}
private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) {
setActiveTransactionsShown(true)
Log.e("TWIG", "setting transaction state to ${transactionState::class.simpleName}")
var title = binding.includeContent.textActiveTransactionTitle.text?.toString() ?: ""
var subtitle = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: ""
var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE
when (transactionState) {
TransactionState.Creating -> {
binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
title = "Preparing ${transaction.value.convertZatoshiToZecString(3)} ZEC"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress}"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
setTransactionActive(transaction, true)
isShown = true
}
TransactionState.SendingToNetwork -> {
title = "Sending Transaction"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress}"
binding.includeContent.textActiveTransactionValue.text = "${transaction.value/1000L}"
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
binding.includeContent.textActiveTransactionValue.text = "${transaction.value.convertZatoshiToZecString(3)}"
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
setTransactionActive(transaction, true)
isShown = true
}
is TransactionState.Failure -> {
binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_failure)
@ -283,21 +284,25 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
binding.includeContent.textActiveTransactionValue.text = transaction.value.convertZatoshiToZecString(3)
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
} else if (transactionState.confirmationCount > 1) {
isShown = false
} else {
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)
setActiveTransactionsShown(false, 5000L)
}
}
is TransactionState.Cancelled -> {
title = binding.includeContent.textActiveTransactionTitle.text.toString()
subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
setTransactionActive(transaction, false)
setActiveTransactionsShown(false, 10000L)
}
}
binding.includeContent.textActiveTransactionTitle.text = title
binding.includeContent.textActiveTransactionSubtitle.text = subtitle
setActiveTransactionsShown(isShown)
}
@ -306,9 +311,10 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
//
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
binding.includeContent.headerActiveTransaction.animate().alpha(if(isShown) 1f else 0f).setDuration(250).setListener(
AnimatorCompleteListener{ binding.includeContent.groupActiveTransactionItems.visibility = if (isShown) View.VISIBLE else View.GONE }
)
}, delay)
}
@ -377,17 +383,7 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
}
speedDial.setOnActionSelectedListener { item ->
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) }
}
HomeFab.fromId(item.id)?.destination?.apply { nav.navigate(this) }
false
}
}
@ -404,8 +400,9 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
.create()
}
private fun setUsdValue(valueString: String) {
val hairSpace = "\u200A"
private fun setUsdValue(value: String) {
val valueString = String.format("$$value")
// val hairSpace = "\u200A"
// val adjustedValue = "$$hairSpace$valueString"
val textSpan = SpannableString(valueString)
textSpan.setSpan(TopAlignedSpan(), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

View File

@ -1,13 +0,0 @@
package cash.z.android.wallet.ui.fragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
class ImportFragment : PlaceholderFragment()
@Module
abstract class ImportFragmentModule {
@ContributesAndroidInjector
abstract fun contributeImportFragment(): ImportFragment
}

View File

@ -23,15 +23,4 @@ open class PlaceholderFragment : BaseFragment() {
return inflater.inflate(R.layout.fragment_placeholder, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(view.findViewById(R.id.toolbar))
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
mainActivity.supportActionBar?.setTitle(R.string.destination_title_placeholder)
}
}
}

View File

@ -0,0 +1,53 @@
package cash.z.android.wallet.ui.fragment
import android.os.Bundle
import android.view.View
import android.widget.ProgressBar
import androidx.annotation.IdRes
import cash.z.android.wallet.ui.presenter.ProgressPresenter
import cash.z.android.wallet.ui.util.AnimatorCompleteListener
import kotlinx.coroutines.launch
abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFragment(),
ProgressPresenter.ProgressView {
private lateinit var progressPresenter: ProgressPresenter
private lateinit var progressBar: ProgressBar
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
progressBar = view.findViewById(progressBarId)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
progressPresenter = ProgressPresenter(this, mainActivity.synchronizer)
}
override fun onResume() {
super.onResume()
launch {
progressPresenter.start()
}
}
override fun onPause() {
super.onPause()
progressPresenter.stop()
}
override fun showProgress(progress: Int) {
if (progress >= 100) {
onProgressComplete()
progressBar.animate().alpha(0.0f).apply {
duration = 250L
setListener(AnimatorCompleteListener {
progressBar.visibility = View.GONE
})
}
}
progressBar.progress = progress
}
open fun onProgressComplete() {}
}

View File

@ -43,11 +43,6 @@ class ReceiveFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(view.findViewById(R.id.toolbar))
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
mainActivity.supportActionBar?.setTitle(R.string.destination_title_receive)
}
addressParts = arrayOf(
text_address_part_1,
text_address_part_2,

View File

@ -49,12 +49,6 @@ class RequestFragment : BaseFragment() {
return inflater.inflate(R.layout.fragment_request, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).setSupportActionBar(view.findViewById(R.id.toolbar))
(activity as MainActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
// TODO: Rename method, update argument and hook method into UI event
fun onButtonPressed(uri: Uri) {
listener?.onFragmentInteraction(uri)

View File

@ -93,11 +93,7 @@ class ScanFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(view.findViewById(R.id.toolbar))
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
mainActivity.supportActionBar?.setTitle(R.string.destination_title_send)
}
// binding.previewCameraSource.doOnLayout {
// if (allPermissionsGranted()) {
// createCameraSource(it.width, it.height)

View File

@ -69,11 +69,6 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).let { mainActivity ->
mainActivity.setSupportActionBar(view.findViewById(R.id.toolbar))
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
mainActivity.supportActionBar?.setTitle(R.string.destination_title_send)
}
init()
}
@ -128,7 +123,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
binding.groupDialogSend.visibility = View.VISIBLE
}
override fun updateBalance(old: Long, new: Long) {
override fun updateBalance(new: Long) {
// TODO: use a formatted string resource here
val availableTextSpan = "${new.convertZatoshiToZecString(8)} $zec Available".toSpannable()
availableTextSpan.setSpan(ForegroundColorSpan(R.color.colorPrimary.toAppColor()), availableTextSpan.length - "Available".length, availableTextSpan.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)

View File

@ -0,0 +1,64 @@
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 cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentSyncBinding
import dagger.Module
import dagger.android.ContributesAndroidInjector
class SyncFragment : ProgressFragment(R.id.progress_sync) {
private lateinit var binding: FragmentSyncBinding
//
// Lifecycle
//
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return DataBindingUtil.inflate<FragmentSyncBinding>(
inflater, R.layout.fragment_sync, container, false
).let {
binding = it
it.root
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonNext.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_home_fragment)
}
}
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(true)
}
override fun onProgressComplete() {
super.onProgressComplete()
binding.textProgressSync.visibility = View.GONE
with (binding.buttonNext) {
isEnabled = true
alpha = 0.3f
animate().alpha(1.0f).duration = 300L
text = "Start"
}
}
}
@Module
abstract class SyncFragmentModule {
@ContributesAndroidInjector
abstract fun contributeSyncFragment(): SyncFragment
}

View File

@ -0,0 +1,123 @@
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.navigation.fragment.FragmentNavigatorExtras
import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentWelcomeBinding
import dagger.Module
import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import android.graphics.Bitmap
import android.R.attr.top
import android.R.attr.left
import android.graphics.RectF
import android.os.Parcelable
import androidx.core.app.ActivityCompat.setExitSharedElementCallback
import android.graphics.Canvas
import android.graphics.Matrix
import android.util.Log
import androidx.core.app.SharedElementCallback
import androidx.transition.TransitionInflater
import cash.z.android.wallet.ui.presenter.ProgressPresenter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
private lateinit var binding: FragmentWelcomeBinding
private lateinit var progressPresenter: ProgressPresenter
//
// Lifecycle
//
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setupSharedElementTransitions()
return DataBindingUtil.inflate<FragmentWelcomeBinding>(
inflater, R.layout.fragment_welcome, container, false
).let {
binding = it
it.root
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
view!!.postDelayed({
launch {
onNext()
}
}, 2000L)
// this.setExitSharedElementCallback(object : SharedElementCallback() {
// override fun onCaptureSharedElementSnapshot(
// sharedElement: View,
// viewToGlobalMatrix: Matrix,
// screenBounds: RectF
// ): Parcelable? {
// val width = Math.round(screenBounds.width())
// val height = Math.round(screenBounds.height())
// var bitmap: Bitmap? = null
// if (width > 0 && height > 0) {
// val matrix = Matrix()
// matrix.set(viewToGlobalMatrix)
// matrix.postTranslate(screenBounds.left, screenBounds.top)
// bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
// val canvas = Canvas(bitmap)
// canvas.concat(matrix)
// sharedElement.draw(canvas)
// }
// return bitmap
// }
// })
}
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(false)
}
private fun setupSharedElementTransitions() {
TransitionInflater.from(mainActivity).inflateTransition(R.transition.transition_zec_sent).apply {
duration = 2500L
this@WelcomeFragment.sharedElementReturnTransition = this
}
}
private suspend fun onNext() = coroutineScope {
val isFirstRun = mainActivity.synchronizer.isFirstRun()
val destination = if (isFirstRun) R.id.nav_firstrun_fragment else R.id.nav_sync_fragment
// var extras = with(binding) {
// listOf(progressWelcome, textProgressWelcome)
// .map { it to it.transitionName }
// .let { FragmentNavigatorExtras(*it.toTypedArray()) }
// }
val extras = FragmentNavigatorExtras(
binding.progressWelcome to binding.progressWelcome.transitionName
)
mainActivity.navController.navigate(
destination,
null,
null,
extras
)
}
}
@Module
abstract class WelcomeFragmentModule {
@ContributesAndroidInjector
abstract fun contributeWelcomeFragment(): WelcomeFragment
}

View File

@ -0,0 +1,50 @@
package cash.z.android.wallet.ui.presenter
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.Twig
import cash.z.wallet.sdk.data.twig
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel
import kotlin.coroutines.CoroutineContext
class ProgressPresenter(
private val view: ProgressView,
private val synchronizer: Synchronizer
) : Presenter, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job
interface ProgressView : PresenterView {
fun showProgress(progress: Int)
}
//
// LifeCycle
//
override suspend fun start() {
Twig.sprout("ProgressPresenter")
twig("starting")
launchProgressMonitor(synchronizer.progress())
}
override fun stop() {
Twig.clip("ProgressPresenter")
twig("stopping")
}
private fun CoroutineScope.launchProgressMonitor(channel: ReceiveChannel<Int>) = launch {
twig("progress monitor starting on thread ${Thread.currentThread().name}!")
for (i in channel) {
bind(i)
}
twig("progress monitor exiting!")
}
private fun bind(progress: Int) = launch {
twig("binding progress of $progress on thread ${Thread.currentThread().name}!")
view.showProgress(progress)
}
}

View File

@ -4,6 +4,7 @@ import android.util.Log
import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.twig
import cash.z.wallet.sdk.ext.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
@ -18,7 +19,7 @@ class SendPresenter(
) : Presenter {
interface SendView : PresenterView {
fun updateBalance(old: Long, new: Long)
fun updateBalance(new: Long)
fun setHeaders(isUsdSelected: Boolean, headerString: String, subheaderString: String)
fun setHeaderValue(usdString: String)
fun setSubheaderValue(usdString: String, isUsdSelected: Boolean)
@ -148,10 +149,8 @@ class SendPresenter(
fun bind(newZecBalance: Long) {
if (newZecBalance >= 0) {
Log.e("@TWIG-v", "binding balance of $newZecBalance")
val old = sendUiModel.zecValue
sendUiModel = sendUiModel.copy(zecValue = newZecBalance)
view.updateBalance(old ?: 0L, newZecBalance)
twig("binding balance of $newZecBalance")
view.updateBalance(newZecBalance)
}
}

View File

@ -0,0 +1,18 @@
package cash.z.android.wallet.ui.util
import android.animation.Animator
class AnimatorCompleteListener(val block: (Animator) -> Unit) : Animator.AnimatorListener {
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator) {
block(animation)
}
override fun onAnimationStart(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@color/zcashGray"/>
<item android:state_enabled="true" android:drawable="@color/colorPrimary" />
</selector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>

View File

@ -0,0 +1,64 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="50dp"
android:height="50dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:pathData="M25,25m-22.75,0a22.75,22.75 0,1 1,45.5 0a22.75,22.75 0,1 1,-45.5 0"
android:strokeLineJoin="round"
android:strokeWidth="0.5"
android:fillColor="#FFFFFF"
android:fillType="evenOdd">
<aapt:attr name="android:strokeColor">
<gradient
android:startY="2.25"
android:startX="25"
android:endY="47.304756"
android:endX="25"
android:type="linear">
<item android:offset="0" android:color="#00000000"/>
<item android:offset="0.8" android:color="#05000000"/>
<item android:offset="1" android:color="#0A000000"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M25,25m-22.75,0a22.75,22.75 0,1 1,45.5 0a22.75,22.75 0,1 1,-45.5 0"
android:strokeLineJoin="round"
android:strokeWidth="0.5"
android:fillColor="#00000000"
android:fillType="evenOdd">
<aapt:attr name="android:strokeColor">
<gradient
android:startY="2.25"
android:startX="25"
android:endY="47.75"
android:endX="25"
android:type="linear">
<item android:offset="0" android:color="#1EFFFFFF"/>
<item android:offset="0.2" android:color="#0FFFFFFF"/>
<item android:offset="1" android:color="#00FFFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M25.0005,2C12.3176,2 2,12.3176 2,24.9995C2,37.6814 12.3176,48 25.0005,48C37.6834,48 48,37.6824 48,24.9995C48,12.3166 37.6824,2 25.0005,2ZM25.0005,44.203C14.4115,44.203 5.797,35.5885 5.797,24.9995C5.797,14.4105 14.4115,5.797 25.0005,5.797C35.5895,5.797 44.203,14.4115 44.203,24.9995C44.203,35.5875 35.5885,44.203 25.0005,44.203Z"
android:strokeWidth="1"
android:fillColor="#231F20"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M24.9747,24.9747m-18.0462,0a18.0462,18.0462 0,1 1,36.0923 0a18.0462,18.0462 0,1 1,-36.0923 0"
android:strokeWidth="1"
android:fillColor="#F4B728"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M33.0626,17.5611l0,-3.5028l-6.2269,0l0,-3.8441l-3.8242,0l0,3.8441l-6.2259,0l0,4.6398l9.6521,0l-7.8934,10.9311l-1.7587,2.2496l0,3.5028l6.2259,0l0,3.8318l0.4587,0l0,0.0163l2.9069,0l0,-0.0163l0.4587,0l0,-3.8318l6.2269,0l0,-4.6398l-9.6532,0l7.8934,-10.9311z"
android:strokeWidth="1"
android:fillColor="#231F20"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -1,28 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
xmlns:tools="http://schemas.android.com/tools">
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
tools:openDrawer="start">
</androidx.drawerlayout.widget.DrawerLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/main_app_bar"
layout="@layout/include_main_app_bar"
tools:ignore="MissingConstraints" />
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
</FrameLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_welcome"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="32dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="32dp" />
<ImageView
android:id="@+id/logo_welcome"
android:layout_width="168dp"
android:layout_height="168dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.17"
app:srcCompat="@drawable/ic_first_run" />
<TextView
android:id="@+id/text_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:gravity="center"
android:text="Welcome to the Zcash\nReference Wallet"
android:textColor="@color/walkthrough_text_header"
android:textSize="@dimen/text_size_h5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/logo_welcome" />
<TextView
android:id="@+id/text_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:gravity="left"
android:justificationMode="inter_word"
android:text="With decentralized wallets, you are the bank.\n\nHaving complete control over your money also makes you responsible for keeping it backed up! This wallet uses funds on TestNet so you can relax!\n\nSince this is an Alpha build, we will import a test seed for demo purposes. We will be starting from scratch so please be patient."
android:textColor="@color/walkthrough_text_body"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@+id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@+id/text_header" />
<ProgressBar
android:id="@+id/progress_firstrun"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:transitionName="@string/transition_walkthrough_progress_bar"
app:layout_constraintBottom_toBottomOf="@+id/button_next"
app:layout_constraintEnd_toStartOf="@+id/button_next"
app:layout_constraintStart_toStartOf="@+id/guideline_content_start" />
<TextView
android:id="@+id/text_progress_firstrun"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:lineSpacingExtra="12dp"
android:paddingEnd="16dp"
android:text="4% reticulating splines"
android:transitionName="@string/transition_walkthrough_progress_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/progress_firstrun"
app:layout_constraintTop_toBottomOf="@+id/progress_firstrun" />
<Button
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:background="@drawable/background_selector_primary_button"
android:text="Got It"
android:textColor="@color/walkthrough_button_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -18,15 +18,12 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appbar"
app:layout_constraintTop_toBottomOf="@+id/main_toolbar"
tools:itemCount="15"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_transaction_history"
tools:orientation="vertical" />
<include
layout="@layout/include_app_bar"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -20,6 +20,16 @@
</com.google.android.material.appbar.AppBarLayout>
<ImageView
android:id="@+id/custom_hamburger"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:onClick="openDrawer"
android:elevation="6dp"
app:srcCompat="@drawable/ic_hamburger"
android:layout_gravity="top|left"/>
<include
android:id="@+id/include_content"
layout="@layout/include_home_content" />

View File

@ -7,9 +7,6 @@
android:layout_height="match_parent"
tools:context=".ui.fragment.PlaceholderFragment">
<include layout="@layout/include_app_bar"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/text_placeholder"
android:layout_width="wrap_content"

View File

@ -13,11 +13,6 @@
android:background="@color/fragment_receive_background"
tools:context=".ui.fragment.ReceiveFragment">
<include
android:id="@+id/include_toolbar"
layout="@layout/include_app_bar"
tools:ignore="MissingConstraints" />
<!-- Shield Background -->
<ImageView
android:id="@+id/image_shield"
@ -28,7 +23,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/include_toolbar"
app:layout_constraintTop_toBottomOf="@+id/main_toolbar"
app:layout_constraintDimensionRatio="H,1:1.1676"
app:layout_constraintVertical_bias="0.062"
app:layout_constraintWidth_default="percent"

View File

@ -8,9 +8,6 @@
android:background="@color/fragment_request_background"
tools:context=".ui.fragment.RequestFragment">
<include layout="@layout/include_app_bar"
tools:ignore="MissingConstraints" />
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/textView4"

View File

@ -44,17 +44,13 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/guideline_content_end" />
<include
layout="@layout/include_app_bar"
tools:ignore="MissingConstraints" />
<View
android:id="@+id/background_header"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/zcashWhite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appbar"
app:layout_constraintTop_toBottomOf="@+id/main_toolbar"
app:layout_constraintVertical_chainStyle="spread" />
<TextView

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_welcome"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="32dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="32dp" />
<ImageView
android:id="@+id/logo_welcome"
android:layout_width="168dp"
android:layout_height="168dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.17"
app:srcCompat="@drawable/ic_sync" />
<TextView
android:id="@+id/text_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:gravity="center"
android:text="What is new in this build?"
android:textColor="@color/walkthrough_text_header"
android:textSize="@dimen/text_size_h5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/logo_welcome" />
<TextView
android:id="@+id/text_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:justificationMode="inter_word"
android:text=" • Everything"
android:textColor="@color/walkthrough_text_body"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@+id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@+id/text_header" />
<ProgressBar
android:id="@+id/progress_sync"
android:transitionName="@string/transition_walkthrough_progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
app:layout_constraintBottom_toBottomOf="@+id/button_next"
app:layout_constraintEnd_toStartOf="@+id/button_next"
app:layout_constraintStart_toStartOf="@+id/guideline_content_start" />
<TextView
android:id="@+id/text_progress_sync"
android:transitionName="@string/transition_walkthrough_progress_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:lineSpacingExtra="12dp"
android:text="4% reticulating splines"
android:paddingEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@+id/progress_sync" />
<Button
android:id="@+id/button_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:background="@drawable/background_selector_primary_button"
android:enabled="false"
android:text="Loading..."
android:textColor="@color/walkthrough_button_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_welcome"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/logo_welcome"
android:layout_width="168dp"
android:layout_height="168dp"
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.333333"
app:srcCompat="@drawable/ic_zcashlogo" />
<TextView
android:id="@+id/text_welcome_zcash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:includeFontPadding="false"
android:text="Zcash"
android:textColor="@color/zcashBlack_87"
android:textSize="84dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/logo_welcome" />
<TextView
android:id="@+id/text_welcome_product_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:text="Reference Wallet Alpha"
android:textColor="@color/text_dark_dimmed"
android:textSize="@dimen/text_size_h5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_welcome_zcash" />
<TextView
android:id="@+id/text_welcome_build_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="PoC v1.2.3 Testnet 2.0.0\nZcash Company - For demo purposes only"
android:textColor="@color/text_dark_dimmed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_welcome_product_name"
app:layout_constraintVertical_bias="0.20" />
<ProgressBar
android:id="@+id/progress_welcome"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:min="0"
android:max="100"
android:transitionName="@string/transition_walkthrough_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/text_welcome_product_name"
app:layout_constraintStart_toStartOf="@id/text_welcome_product_name"
app:layout_constraintTop_toBottomOf="@+id/text_welcome_build_info" />
<!-- not animating properly so hide this for now -->
<TextView
android:id="@+id/text_progress_welcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:singleLine="true"
android:text="4% reticulating splines"
android:textAlignment="center"
android:transitionName="@string/transition_walkthrough_progress_text"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/progress_welcome"
app:layout_constraintTop_toBottomOf="@+id/progress_welcome" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -54,6 +54,7 @@
android:paddingRight="8dp"
android:paddingBottom="16dp"
android:transitionName="@string/transition_active_transaction_card"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_active_transaction_header"
tools:visibility="visible">

View File

@ -2,16 +2,16 @@
<com.google.android.material.appbar.AppBarLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/appbar"
android:id="@+id/main_app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ZcashTheme.AppBarOverlay"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:showIn="@layout/fragment_send">
tools:showIn="@layout/activity_main">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ZcashTheme.PopupOverlay" />

View File

@ -1,45 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/image_nav_header_logo"
android:layout_width="92dp"
android:layout_height="92dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/nav_header_desc"
app:srcCompat="@drawable/zcash_logo_with_shadow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/text_nav_header_title"
app:layout_constraintDimensionRatio="1:1"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<TextView
android:id="@+id/text_nav_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBottom_toTopOf="@id/text_nav_header_subtitle"
app:layout_constraintLeft_toLeftOf="@id/text_nav_header_subtitle"/>
<ImageView
android:id="@+id/image_nav_header_logo"
android:layout_width="92dp"
android:layout_height="92dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/nav_header_desc"
app:srcCompat="@drawable/zcash_logo_with_shadow"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/text_nav_header_title"
app:layout_constraintDimensionRatio="1:1" />
<TextView
android:id="@+id/text_nav_header_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/text_nav_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBottom_toTopOf="@id/text_nav_header_subtitle"
app:layout_constraintLeft_toLeftOf="@id/text_nav_header_subtitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/text_nav_header_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -6,10 +6,6 @@
<group
android:id="@+id/fab_actions"
android:checkableBehavior="single">
<!--<item-->
<!--android:id="@+id/nav_home_fragment"-->
<!--android:icon="@drawable/ic_home_black_24dp"-->
<!--android:title="@string/destination_menu_label_home"/>-->
<item
android:id="@+id/nav_send_fragment"
android:icon="@drawable/ic_menu_send"
@ -35,26 +31,11 @@
android:id="@+id/nav_about_fragment"
android:icon="@drawable/ic_chat_24dp"
android:title="@string/destination_menu_label_about" />
<item
android:id="@+id/nav_import_fragment"
android:icon="@drawable/ic_import"
android:title="@string/destination_menu_label_import" />
<item
android:id="@+id/nav_settings_fragment"
android:icon="@drawable/ic_settings_24dp"
android:title="@string/destination_menu_label_settings" />
</group>
<!--<item android:title="Communicate" >-->
<!--<menu>-->
<!--<item-->
<!--android:id="@+id/nav_share"-->
<!--android:icon="@drawable/ic_menu_share"-->
<!--android:title="Share"/>-->
<!--<item-->
<!--android:id="@+id/nav_send"-->
<!--android:icon="@drawable/ic_menu_send"-->
<!--android:title="Send"/>-->
<!--</menu>-->
<!--</item>-->
</menu>

View File

@ -3,8 +3,41 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@id/nav_home_fragment">
app:startDestination="@id/nav_welcome_fragment">
<fragment
android:id="@+id/nav_welcome_fragment"
android:name="cash.z.android.wallet.ui.fragment.WelcomeFragment"
android:label="@string/destination_title_welcome"
tools:layout="@layout/fragment_welcome">
<action
android:id="@+id/action_welcome_fragment_to_firstrun_fragment"
app:destination="@id/nav_firstrun_fragment" />
<action
android:id="@+id/action_welcome_fragment_to_sync_fragment"
app:destination="@id/nav_sync_fragment" />
<action
android:id="@+id/action_welcome_fragment_to_home_fragment"
app:destination="@id/nav_home_fragment" />
</fragment>
<fragment
android:id="@+id/nav_firstrun_fragment"
android:name="cash.z.android.wallet.ui.fragment.FirstrunFragment"
android:label="@string/destination_title_firstrun"
tools:layout="@layout/fragment_firstrun">
<action
android:id="@+id/action_firstrun_fragment_to_sync_fragment"
app:destination="@id/nav_sync_fragment" />
</fragment>
<fragment
android:id="@+id/nav_sync_fragment"
android:name="cash.z.android.wallet.ui.fragment.SyncFragment"
android:label="@string/destination_title_sync"
tools:layout="@layout/fragment_sync">
<action
android:id="@+id/action_sync_fragment_to_home_fragment"
app:destination="@id/nav_home_fragment" />
</fragment>
<fragment
android:id="@+id/nav_home_fragment"
android:name="cash.z.android.wallet.ui.fragment.HomeFragment"
@ -19,15 +52,15 @@
<action
android:id="@+id/action_home_fragment_to_request_fragment"
app:destination="@id/nav_request_fragment" />
<action
android:id="@+id/action_home_fragment_to_history_fragment"
app:destination="@id/nav_history_fragment" />
</fragment>
<fragment
android:id="@+id/nav_send_fragment"
android:name="cash.z.android.wallet.ui.fragment.SendFragment"
android:label="@string/destination_title_send"
tools:layout="@layout/fragment_send" >
<action
android:id="@+id/action_send_fragment_to_scan_fragment"
app:destination="@+id/nav_scan_fragment" />
</fragment>
<fragment
android:id="@+id/nav_receive_fragment"
@ -39,28 +72,18 @@
android:name="cash.z.android.wallet.ui.fragment.RequestFragment"
android:label="@string/destination_title_request"
tools:layout="@layout/fragment_request" />
<fragment
android:id="@+id/nav_scan_fragment"
android:name="cash.z.android.wallet.ui.fragment.ScanFragment"
android:label="@string/destination_title_scan"
tools:layout="@layout/fragment_scan" />
<!-- unimplemented -->
<fragment
android:id="@+id/nav_history_fragment"
android:name="cash.z.android.wallet.ui.fragment.HistoryFragment"
android:label="@string/destination_title_history"
tools:layout="@layout/fragment_placeholder" />
<!-- unimplemented -->
<fragment
android:id="@+id/nav_about_fragment"
android:name="cash.z.android.wallet.ui.fragment.AboutFragment"
android:label="@string/destination_title_about"
tools:layout="@layout/fragment_placeholder" />
<fragment
android:id="@+id/nav_import_fragment"
android:name="cash.z.android.wallet.ui.fragment.ImportFragment"
android:label="@string/destination_title_import"
tools:layout="@layout/fragment_placeholder" />
<fragment
android:id="@+id/nav_settings_fragment"
android:name="cash.z.android.wallet.ui.fragment.SettingsFragment"

View File

@ -3,16 +3,20 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together">
<changeBounds>
<arcMotion/>
</changeBounds>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
<slide
android:slideEdge="left"
android:duration="200"
android:interpolator="@android:interpolator/linear_out_slow_in"/>
<autoTransition/>
<!--<changeBounds>-->
<!--&lt;!&ndash;<arcMotion/>&ndash;&gt;-->
<!--</changeBounds>-->
<!--<changeTransform/>-->
<!--<changeClipBounds/>-->
<!--<changeImageTransform/>-->
<!--<slide-->
<!--android:slideEdge="bottom"-->
<!--android:duration="200"-->
<!--android:interpolator="@android:interpolator/linear_out_slow_in"/>-->
<!--<changeBounds android:interpolator="@android:interpolator/fast_out_slow_in">-->
<!--<targets>-->
<!--<target android:targetName="@string/transition_active_transaction" />-->

View File

@ -21,6 +21,7 @@
<color name="zcashBlue">#2196F3</color>
<color name="zcashBlueGray">#0D364C66</color>
<color name="zcashBlueGray_dark">#2A4E5D</color>
<color name="zcashWhite">#FFFFFF</color>
<color name="zcashWhite_12">#1FFFFFFF</color>
<color name="zcashWhite_40">#66FFFFFF</color>
@ -28,6 +29,7 @@
<color name="zcashWhite_87">#BFFFFFFF</color>
<color name="zcashWhite_light">#EDEDED</color>
<color name="zcashGray_light">#CACACA</color>
<color name="zcashGray_dark">#4A4A4A</color>
<color name="zcashGray">#9B9B9B</color>
<color name="zcashBlack_light">#2B2B2B</color>
<color name="zcashBlack_12">#1F000000</color>
@ -75,6 +77,12 @@
<color name="home_transaction_item_background">@color/zcashBlueGray</color>
<color name="divider_background">@color/zcashBlack_12</color>
<!-- content -->
<color name="walkthrough_text_header">@color/zcashBlueGray_dark</color>
<color name="walkthrough_text_body">@color/zcashGray_dark</color>
<color name="walkthrough_button_text">@color/text_light</color>
<!-- controls -->
<color name="progress_bar_active">@color/zcashBlack_12</color>

View File

@ -15,14 +15,15 @@
<string name="usd_abbreviation">USD</string>
<!-- Destinations -->
<string name="destination_title_home" />
<string name="destination_title_home" ></string>
<string name="destination_title_send">Send Zcash</string>
<string name="destination_title_receive">Receive Zcash</string>
<string name="destination_title_request">Request Zcash</string>
<string name="destination_title_scan">Scan Address</string>
<string name="destination_title_welcome"></string>
<string name="destination_title_firstrun">Getting Started</string>
<string name="destination_title_sync">Release Notes</string>
<string name="destination_title_history">History</string>
<string name="destination_title_about">About</string>
<string name="destination_title_import">Import</string>
<string name="destination_title_settings">Settings</string>
<string name="destination_title_placeholder">Coming Soon</string>
<string name="destination_menu_label_home">Home</string>
@ -31,7 +32,6 @@
<string name="destination_menu_label_request">Request</string>
<string name="destination_menu_label_about">About</string>
<string name="destination_menu_label_history">History</string>
<string name="destination_menu_label_import">Import</string>
<string name="destination_menu_label_settings">Settings</string>
<!-- Transitions -->
@ -39,6 +39,8 @@
<string name="transition_active_transaction_title">transition_active_transaction_title</string>
<string name="transition_active_transaction_address">transition_active_transaction_address</string>
<string name="transition_active_transaction_card">transition_active_transaction_card</string>
<string name="transition_walkthrough_progress_bar">transition_walkthrough_progress_bar</string>
<string name="transition_walkthrough_progress_text">transition_walkthrough_progress_text</string>
<!-- -->

View File

@ -15,6 +15,11 @@ import javax.inject.Singleton
@Module
internal object SynchronizerModule {
const val MOCK_TX_INTERVAL = 30_000L
const val MOCK_LOAD_DURATION = 5_000L
const val MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL = 5_000L
@JvmStatic
@Provides
@Singleton
@ -28,8 +33,9 @@ internal object SynchronizerModule {
@Singleton
fun provideSynchronizer(): Synchronizer {
return MockSynchronizer(
transactionInterval = 60_000L,
activeTransactionUpdateFrequency = 18_000L,
transactionInterval = MOCK_TX_INTERVAL,
initialLoadDuration = MOCK_LOAD_DURATION,
activeTransactionUpdateFrequency = MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL,
isFirstRun = true
)
}