2018-11-12 10:38:37 -08:00
package cash.z.android.wallet.ui.fragment
import android.os.Bundle
2018-12-07 09:14:54 -08:00
import android.text.SpannableString
import android.text.Spanned
2019-01-31 12:44:25 -08:00
import android.util.Log
2018-11-21 02:11:48 -08:00
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
2019-02-02 14:47:08 -08:00
import android.view.animation.AccelerateInterpolator
2019-02-07 19:18:32 -08:00
import android.view.animation.DecelerateInterpolator
2018-12-02 20:45:59 -08:00
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.annotation.StringRes
2019-02-14 17:26:56 -08:00
import androidx.databinding.DataBindingUtil
2018-12-07 16:27:57 -08:00
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
2019-02-14 17:26:56 -08:00
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
2019-02-02 07:07:25 -08:00
import androidx.transition.Transition
2019-02-01 08:10:43 -08:00
import androidx.transition.TransitionInflater
2018-11-12 10:38:37 -08:00
import cash.z.android.wallet.R
2019-02-14 17:26:56 -08:00
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
2018-12-07 16:27:57 -08:00
import cash.z.android.wallet.ui.adapter.TransactionAdapter
2018-12-30 17:37:43 -08:00
import cash.z.android.wallet.ui.presenter.HomePresenter
2018-12-30 18:41:47 -08:00
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
2019-02-14 17:26:56 -08:00
import cash.z.android.wallet.ui.util.LottieLooper
2018-12-07 09:14:54 -08:00
import cash.z.android.wallet.ui.util.TopAlignedSpan
2019-02-07 19:18:32 -08:00
import cash.z.wallet.sdk.dao.WalletTransaction
2019-02-04 10:42:28 -08:00
import cash.z.wallet.sdk.data.ActiveSendTransaction
2019-02-03 17:27:54 -08:00
import cash.z.wallet.sdk.data.ActiveTransaction
import cash.z.wallet.sdk.data.TransactionState
2019-02-04 10:42:28 -08:00
import cash.z.wallet.sdk.ext.toZec
2019-02-07 19:18:32 -08:00
import com.google.android.material.snackbar.Snackbar
2018-12-02 19:21:23 -08:00
import com.leinardi.android.speeddial.SpeedDialActionItem
2018-12-04 23:26:03 -08:00
import dagger.Module
import dagger.android.ContributesAndroidInjector
2018-12-30 17:37:43 -08:00
import kotlinx.coroutines.launch
2018-12-07 16:27:57 -08:00
import kotlin.random.Random
2019-02-03 23:08:26 -08:00
import kotlin.random.nextLong
2019-01-31 14:47:37 -08:00
2018-11-12 10:38:37 -08:00
/ * *
2018-12-02 20:45:59 -08:00
* Fragment representing the home screen of the app . This is the screen most often seen by the user when launching the
* application .
2018-11-12 10:38:37 -08:00
* /
2019-02-14 17:26:56 -08:00
class HomeFragment : BaseFragment ( ) , SwipeRefreshLayout . OnRefreshListener , HomePresenter . HomeView {
2018-11-21 02:11:48 -08:00
2019-02-14 17:26:56 -08:00
private lateinit var homePresenter : HomePresenter
private lateinit var binding : FragmentHomeBinding
private lateinit var zcashLogoAnimation : LottieLooper
2019-02-07 19:18:32 -08:00
private var snackbar : Snackbar ? = null
2019-02-14 17:26:56 -08:00
private var viewsInitialized = false
2018-12-30 17:37:43 -08:00
2018-11-12 10:38:37 -08:00
override fun onCreateView (
inflater : LayoutInflater , container : ViewGroup ? ,
savedInstanceState : Bundle ?
) : View ? {
2019-01-31 12:44:25 -08:00
viewsInitialized = false
2019-02-14 17:26:56 -08:00
// setupSharedElementTransitions()
return DataBindingUtil . inflate < FragmentHomeBinding > (
inflater , R . layout . fragment _home , container , false
) . let {
binding = it
it . root
}
2019-02-02 14:47:08 -08:00
}
2019-02-02 07:07:25 -08:00
2019-02-02 14:47:08 -08:00
private fun setupSharedElementTransitions ( ) {
2019-02-14 17:26:56 -08:00
TransitionInflater . from ( mainActivity ) . inflateTransition ( R . transition . transition _zec _sent ) . apply {
duration = 3000L
addListener ( HomeTransitionListener ( ) )
this @HomeFragment . sharedElementEnterTransition = this
this @HomeFragment . sharedElementReturnTransition = this
}
2018-11-12 10:38:37 -08:00
}
2019-02-14 17:26:56 -08:00
2018-11-13 21:16:53 -08:00
override fun onViewCreated ( view : View , savedInstanceState : Bundle ? ) {
super . onViewCreated ( view , savedInstanceState )
2019-02-14 17:26:56 -08:00
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?")
// }
}
2019-02-02 07:07:25 -08:00
2019-02-14 17:26:56 -08:00
override fun onActivityCreated ( savedInstanceState : Bundle ? ) {
super . onActivityCreated ( savedInstanceState )
with ( mainActivity ) {
setSupportActionBar ( binding . includeHeader . homeToolbar )
setupNavigation ( )
supportActionBar ?. setTitle ( R . string . destination _title _home )
2019-02-01 19:35:45 -08:00
}
2019-02-14 17:26:56 -08:00
initFab ( )
2019-02-03 23:08:26 -08:00
2019-02-14 17:26:56 -08:00
homePresenter = HomePresenter ( this , mainActivity . synchronizer )
2019-02-03 23:08:26 -08:00
2019-02-14 17:26:56 -08:00
binding . includeContent . recyclerTransactions . apply {
layoutManager = LinearLayoutManager ( activity , RecyclerView . VERTICAL , false )
adapter = TransactionAdapter ( )
addItemDecoration ( AlternatingRowColorDecoration ( ) )
2019-02-03 23:08:26 -08:00
}
2018-11-13 21:16:53 -08:00
}
2018-12-07 16:27:57 -08:00
override fun onResume ( ) {
super . onResume ( )
2019-01-29 10:08:33 -08:00
launch {
homePresenter . start ( )
}
2018-12-30 17:37:43 -08:00
}
override fun onPause ( ) {
super . onPause ( )
2019-01-29 10:08:33 -08:00
homePresenter . stop ( )
2019-02-14 17:26:56 -08:00
binding . lottieZcashBadge . cancelAnimation ( )
2018-12-07 16:27:57 -08:00
}
2019-02-14 17:26:56 -08:00
//
// 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
2019-02-03 23:08:26 -08:00
}
2019-02-14 17:26:56 -08:00
toggleViews ( !is Shown )
}
2019-02-03 23:08:26 -08:00
2019-02-14 17:26:56 -08:00
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 )
}
}
2018-12-07 16:27:57 -08:00
2019-02-12 16:09:06 -08:00
2019-02-14 17:26:56 -08:00
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 )
2018-12-30 18:41:47 -08:00
}
2018-12-02 19:21:23 -08:00
}
2018-12-30 18:41:47 -08:00
2019-02-14 17:26:56 -08:00
2019-02-07 19:18:32 -08:00
//TODO: pull some of this logic into the presenter, particularly the part that deals with ZEC <-> USD price conversion
2019-01-29 10:08:33 -08:00
override fun updateBalance ( old : Long , new : Long ) {
2019-01-31 12:44:25 -08:00
val zecValue = new / 1 e8
2018-12-30 18:41:47 -08:00
setZecValue ( zecValue )
2019-02-14 17:26:56 -08:00
setUsdValue ( SampleProperties . USD _PER _ZEC * zecValue )
onContentRefreshComplete ( zecValue )
2018-12-30 18:41:47 -08:00
}
2019-01-31 12:44:25 -08:00
override fun setTransactions ( transactions : List < WalletTransaction > ) {
2019-02-14 17:26:56 -08:00
with ( binding . includeContent . recyclerTransactions ) {
( adapter as TransactionAdapter ) . submitList ( transactions )
postDelayed ( {
smoothScrollToPosition ( 0 )
} , 100L )
if ( binding . includeFirstRun . visibility == View . VISIBLE ) setFirstRunShown ( false )
}
2018-12-30 18:41:47 -08:00
}
2019-01-29 10:08:33 -08:00
override fun showProgress ( progress : Int ) {
2019-02-14 17:26:56 -08:00
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")
2019-01-31 14:47:37 -08:00
// 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)
//
2019-02-14 17:26:56 -08:00
// 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()
// }
2019-01-29 10:08:33 -08:00
}
2019-02-14 17:26:56 -08:00
private fun onInitialLoadComplete ( ) {
val isEmpty = ( binding . includeContent . recyclerTransactions ?. adapter ?. itemCount ?: 0 ) . let { it == 0 }
Log . e ( " TWIG-t " , " onInitialLoadComplete and isEmpty == $isEmpty " )
setContentViewShown ( !is Empty )
if ( isEmpty ) {
binding . includeContent . textEmptyWalletMessage . setText ( R . string . home _empty _wallet )
2019-02-07 19:18:32 -08:00
}
2019-02-14 17:26:56 -08:00
setRefreshAnimationPlaying ( false ) . also { Log . e ( " TWIG-a " , " refresh false from onInitialLoadComplete " ) }
2019-02-07 19:18:32 -08:00
}
2019-02-14 17:26:56 -08:00
2019-02-03 17:27:54 -08:00
override fun setActiveTransactions ( activeTransactionMap : Map < ActiveTransaction , TransactionState > ) {
if ( activeTransactionMap . isEmpty ( ) ) {
setActiveTransactionsShown ( false )
return
}
val transactions = activeTransactionMap . entries . toTypedArray ( )
// primary is the last one that was inserted
val primaryEntry = transactions [ transactions . size - 1 ]
updatePrimaryTransaction ( primaryEntry . key , primaryEntry . value )
// TODO: update remaining transactions
}
2019-02-07 19:18:32 -08:00
override fun onCancelledTooLate ( ) {
2019-02-14 17:26:56 -08:00
snackbar = snackbar . showOk ( view !! , " Oops! It was too late to cancel! " )
2019-02-07 19:18:32 -08:00
}
2019-02-03 17:27:54 -08:00
private fun updatePrimaryTransaction ( transaction : ActiveTransaction , transactionState : TransactionState ) {
2019-02-14 17:26:56 -08:00
setActiveTransactionsShown ( true )
2019-02-07 19:18:32 -08:00
Log . e ( " TWIG " , " setting transaction state to ${transactionState::class.simpleName} " )
2019-02-03 17:27:54 -08:00
var title = " Active Transaction "
var subtitle = " Processing... "
when ( transactionState ) {
TransactionState . Creating -> {
2019-02-14 17:26:56 -08:00
binding . includeContent . headerActiveTransaction . visibility = View . VISIBLE
2019-02-04 11:11:22 -08:00
title = " Preparing ${transaction.value.toZec(3)} ZEC "
2019-02-04 10:42:28 -08:00
subtitle = " to ${(transaction as ActiveSendTransaction).toAddress} "
2019-02-07 19:18:32 -08:00
setTransactionActive ( transaction , true )
2019-02-03 17:27:54 -08:00
}
TransactionState . SendingToNetwork -> {
title = " Sending Transaction "
2019-02-04 10:42:28 -08:00
subtitle = " to ${(transaction as ActiveSendTransaction).toAddress} "
2019-02-14 17:26:56 -08:00
binding . includeContent . textActiveTransactionValue . text = " ${transaction.value/1000L} "
binding . includeContent . textActiveTransactionValue . visibility = View . VISIBLE
binding . includeContent . buttonActiveTransactionCancel . visibility = View . GONE
2019-02-03 17:27:54 -08:00
}
is TransactionState . Failure -> {
2019-02-14 17:26:56 -08:00
binding . includeContent . lottieActiveTransaction . setAnimation ( R . raw . lottie _send _failure )
binding . includeContent . lottieActiveTransaction . playAnimation ( )
2019-02-03 17:27:54 -08:00
title = " Failed "
subtitle = when ( transactionState . failedStep ) {
TransactionState . Creating -> " Failed to create transaction "
TransactionState . SendingToNetwork -> " Failed to submit transaction to the network "
else -> " Unrecoginzed error "
}
2019-02-14 17:26:56 -08:00
binding . includeContent . buttonActiveTransactionCancel . visibility = View . GONE
binding . includeContent . textActiveTransactionValue . visibility = View . GONE
2019-02-07 19:18:32 -08:00
setTransactionActive ( transaction , false )
2019-02-14 17:26:56 -08:00
setActiveTransactionsShown ( false , 10000L )
2019-02-03 17:27:54 -08:00
}
is TransactionState . AwaitingConfirmations -> {
2019-02-03 23:08:26 -08:00
if ( transactionState . confirmationCount < 1 ) {
2019-02-14 17:26:56 -08:00
binding . includeContent . lottieActiveTransaction . setAnimation ( R . raw . lottie _send _success )
binding . includeContent . lottieActiveTransaction . playAnimation ( )
2019-02-03 23:08:26 -08:00
title = " ZEC Sent "
2019-02-14 17:26:56 -08:00
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
2019-02-03 23:08:26 -08:00
} else {
2019-02-14 17:26:56 -08:00
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 )
2019-02-03 23:08:26 -08:00
}
2019-02-03 17:27:54 -08:00
}
2019-02-07 19:18:32 -08:00
is TransactionState . Cancelled -> {
2019-02-14 17:26:56 -08:00
title = binding . includeContent . textActiveTransactionTitle . text . toString ( )
subtitle = binding . includeContent . textActiveTransactionSubtitle . text . toString ( )
2019-02-07 19:18:32 -08:00
setTransactionActive ( transaction , false )
}
2019-02-03 17:27:54 -08:00
}
2019-02-14 17:26:56 -08:00
binding . includeContent . textActiveTransactionTitle . text = title
binding . includeContent . textActiveTransactionSubtitle . text = subtitle
2019-02-03 17:27:54 -08:00
}
2019-02-02 07:07:25 -08:00
2018-12-30 18:41:47 -08:00
//
2019-02-02 07:07:25 -08:00
// Private View API
2018-12-30 18:41:47 -08:00
//
2019-02-14 17:26:56 -08:00
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 ( !is Shown ) View . VISIBLE else View . GONE
binding . lottieZcashBadge . visibility = if ( !is Shown ) View . VISIBLE else View . GONE
}
2018-12-02 20:45:59 -08:00
/ * *
2019-02-14 17:26:56 -08:00
* General initialization called during onViewCreated . Mostly responsible for applying the default empty state of
* the view , before any data or information is known .
2018-12-02 20:45:59 -08:00
* /
2019-02-14 17:26:56 -08:00
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
2018-12-02 20:45:59 -08:00
HomeFab . values ( ) . forEach {
2018-12-06 23:16:51 -08:00
speedDial . addActionItem ( it . createItem ( ) )
2018-12-02 20:45:59 -08:00
}
2018-12-02 19:21:23 -08:00
speedDial . setOnActionSelectedListener { item ->
2019-02-14 17:26:56 -08:00
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 ) }
}
2018-12-02 19:21:23 -08:00
false
}
}
2019-02-14 17:26:56 -08:00
/ * *
* Helper for creating fablets -- those little buttons that pop up when the fab is tapped .
* /
2018-12-06 23:16:51 -08:00
private val createItem : HomeFab . ( ) -> SpeedDialActionItem = {
SpeedDialActionItem . Builder ( id , icon )
. setFabBackgroundColor ( bgColor . toAppColor ( ) )
. setFabImageTintColor ( R . color . zcashWhite . toAppColor ( ) )
. setLabel ( label . toAppString ( ) )
. setLabelClickable ( true )
. create ( )
}
2018-12-30 17:56:50 -08:00
private fun setUsdValue ( value : Double ) {
2018-12-10 08:38:03 -08:00
val valueString = String . format ( " $ %,.2f" , value )
val hairSpace = " \u200A "
// val adjustedValue = "$$hairSpace$valueString"
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 )
2019-02-14 17:26:56 -08:00
binding . includeHeader . textBalanceUsd . text = textSpan
2018-12-07 09:14:54 -08:00
}
2018-12-30 17:56:50 -08:00
private fun setZecValue ( value : Double ) {
2019-02-14 17:26:56 -08:00
binding . includeHeader . textBalanceZec . text = if ( value == 0.0 ) " 0 " else String . format ( " %.3f " , value )
2018-12-10 08:38:03 -08:00
// // 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"
// text_balance_zec.text = adjustedValue
}
2019-01-31 12:44:25 -08:00
/ * *
2019-02-14 17:26:56 -08:00
* Called whenever the content has been refreshed on the screen . When it is time to show and hide things .
2019-01-31 12:44:25 -08:00
* 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 .
* /
2019-02-14 17:26:56 -08:00
private fun onContentRefreshComplete ( value : Double ) {
2019-01-31 12:44:25 -08:00
val isEmpty = value <= 0.0
// wasEmpty isn't enough info. it must be considered along with whether these views were ever initialized
2019-02-14 17:26:56 -08:00
val wasEmpty = binding . includeContent . groupEmptyViewItems . visibility == View . VISIBLE
2019-01-31 12:44:25 -08:00
// 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! " )
2019-02-14 17:26:56 -08:00
setContentViewShown ( !is Empty )
2019-02-04 10:42:28 -08:00
if ( !is Empty ) setFirstRunShown ( false )
2018-12-30 17:56:50 -08:00
}
2019-02-14 17:26:56 -08:00
setRefreshAnimationPlaying ( false ) . also { Log . e ( " TWIG-a " , " refresh false from onContentRefreshComplete " ) }
binding . includeHeader . containerHomeHeader . visibility = View . VISIBLE
2018-12-30 17:56:50 -08:00
}
2019-02-03 17:27:54 -08:00
private fun onActiveTransactionTransitionStart ( ) {
2019-02-14 17:26:56 -08:00
binding . includeContent . buttonActiveTransactionCancel . visibility = View . INVISIBLE
2019-02-03 17:27:54 -08:00
}
private fun onActiveTransactionTransitionEnd ( ) {
2019-02-07 19:18:32 -08:00
// TODO: investigate if this fix is still required after getting transition animation working again
2019-02-03 17:27:54 -08:00
// 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
2019-02-14 17:26:56 -08:00
binding . includeContent . headerActiveTransaction . translationZ = 10.0f
binding . includeContent . buttonActiveTransactionCancel . apply {
2019-02-03 23:08:26 -08:00
postDelayed ( { text = " cancel " } , 50L )
2019-02-04 10:42:28 -08:00
visibility = View . VISIBLE
2019-02-03 23:08:26 -08:00
}
2019-02-03 17:27:54 -08:00
}
2019-02-07 19:18:32 -08:00
private fun setTransactionActive ( transaction : ActiveTransaction , isActive : Boolean ) {
// TODO: get view for transaction, mostly likely keep a sparse array of these or something
if ( isActive ) {
2019-02-14 17:26:56 -08:00
binding . includeContent . buttonActiveTransactionCancel . setText ( R . string . cancel )
binding . includeContent . buttonActiveTransactionCancel . isEnabled = true
binding . includeContent . buttonActiveTransactionCancel . tag = transaction
binding . includeContent . headerActiveTransaction . animate ( ) . apply {
2019-02-07 19:18:32 -08:00
translationZ ( 10f )
duration = 200L
interpolator = DecelerateInterpolator ( )
}
} else {
2019-02-14 17:26:56 -08:00
binding . includeContent . buttonActiveTransactionCancel . setText ( R . string . cancelled )
binding . includeContent . buttonActiveTransactionCancel . isEnabled = false
binding . includeContent . buttonActiveTransactionCancel . tag = null
binding . includeContent . headerActiveTransaction . animate ( ) . apply {
2019-02-07 19:18:32 -08:00
translationZ ( 2f )
duration = 300L
interpolator = AccelerateInterpolator ( )
}
2019-02-14 17:26:56 -08:00
binding . includeContent . lottieActiveTransaction . cancelAnimation ( )
2019-02-02 14:47:08 -08:00
}
2019-02-02 07:07:25 -08:00
}
2019-02-03 17:27:54 -08:00
2018-11-12 10:38:37 -08:00
/ * *
2018-12-02 20:45:59 -08:00
* Defines the basic properties of each FAB button for use while initializing the FAB
2018-11-12 10:38:37 -08:00
* /
2018-12-02 20:45:59 -08:00
enum class HomeFab (
@IdRes val id : Int ,
@DrawableRes val icon : Int ,
@ColorRes val bgColor : Int ,
@StringRes val label : Int ,
@IdRes val destination : Int
) {
/* ordered by when they need to be added to the speed dial (i.e. reverse display order) */
REQUEST (
R . id . fab _request ,
R . drawable . ic _receipt _24dp ,
R . color . icon _request ,
R . string . destination _menu _label _request ,
R . id . nav _request _fragment
) ,
RECEIVE (
R . id . fab _receive ,
R . drawable . ic _qrcode _24dp ,
R . color . icon _receive ,
R . string . destination _menu _label _receive ,
R . id . nav _receive _fragment
) ,
SEND (
R . id . fab _send ,
R . drawable . ic _menu _send ,
R . color . icon _send ,
R . string . destination _menu _label _send ,
R . id . nav _send _fragment
) ;
companion object {
fun fromId ( id : Int ) : HomeFab ? = values ( ) . firstOrNull { it . id == id }
}
2018-11-12 10:38:37 -08:00
}
2019-02-14 17:26:56 -08:00
//
//
//
//// ---------------------------------------------------------------------------------------------------------------------
//// TODO: Delete these test functions
//// ---------------------------------------------------------------------------------------------------------------------
//
2018-12-10 08:38:03 -08:00
var empty = false
2019-01-31 12:44:25 -08:00
val delay = 50L
2018-12-10 08:38:03 -08:00
lateinit var headerEmptyViews : Array < View >
lateinit var headerFullViews : Array < View >
fun shrink ( ) : Double {
2019-02-14 17:26:56 -08:00
return binding . includeHeader . textBalanceZec . text . toString ( ) . trim ( ) . toDouble ( ) - Random . nextDouble ( 5.0 )
2018-12-10 08:38:03 -08:00
}
fun grow ( ) : Double {
2019-02-14 17:26:56 -08:00
return binding . includeHeader . textBalanceZec . text . toString ( ) . trim ( ) . toDouble ( ) + Random . nextDouble ( 5.0 )
2018-12-10 08:38:03 -08:00
}
fun reduceValue ( ) {
shrink ( ) . let {
if ( it < 0 ) { setZecValue ( 0.0 ) ; toggleViews ( empty ) ; forceRedraw ( ) }
else view ?. postDelayed ( {
setZecValue ( it )
setUsdValue ( it * 75.0 )
reduceValue ( )
} , delay )
}
}
fun increaseValue ( target : Double ) {
grow ( ) . let {
if ( it > target ) { setZecValue ( target ) ; setUsdValue ( target * 75.0 ) ; toggleViews ( empty ) }
else view ?. postDelayed ( {
setZecValue ( it )
setUsdValue ( it * 75.0 )
increaseValue ( target )
if ( headerFullViews [ 0 ] . parent == null || headerEmptyViews [ 0 ] . parent != null ) toggleViews ( false )
forceRedraw ( )
} , delay )
}
}
fun forceRedraw ( ) {
view ?. postDelayed ( {
2019-02-14 17:26:56 -08:00
binding . includeHeader . containerHomeHeader . progress = binding . includeHeader . containerHomeHeader . progress - 0.1f
2018-12-10 08:38:03 -08:00
} , delay * 2 )
}
internal fun toggle ( isEmpty : Boolean ) {
toggleValues ( isEmpty )
}
2019-01-31 12:44:25 -08:00
2018-12-10 08:38:03 -08:00
internal fun toggleViews ( isEmpty : Boolean ) {
2019-01-31 12:44:25 -08:00
Log . e ( " TWIG-t " , " toggling views to isEmpty == $isEmpty " )
var action : ( ) -> Unit
if ( isEmpty ) {
action = {
2019-02-14 17:26:56 -08:00
binding . includeContent . groupEmptyViewItems . visibility = View . VISIBLE
binding . includeContent . groupContentViewItems . visibility = View . GONE
headerFullViews . forEach { binding . includeHeader . containerHomeHeader . removeView ( it ) }
headerEmptyViews . forEach {
tryIgnore {
binding . includeHeader . containerHomeHeader . addView ( it )
}
}
}
} else {
action = {
binding . includeContent . groupEmptyViewItems . visibility = View . GONE
binding . includeContent . groupContentViewItems . visibility = View . VISIBLE
headerEmptyViews . forEach { binding . includeHeader . containerHomeHeader . removeView ( it ) }
headerFullViews . forEach {
tryIgnore {
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 ) }
2018-12-10 08:38:03 -08:00
headerEmptyViews . forEach {
tryIgnore {
2019-02-14 17:26:56 -08:00
binding . includeHeader . containerHomeHeader . addView ( it )
2018-12-10 08:38:03 -08:00
}
}
2019-01-31 12:44:25 -08:00
}
2018-12-10 08:38:03 -08:00
} else {
2019-01-31 12:44:25 -08:00
action = {
2019-02-14 17:26:56 -08:00
// group_empty_view_items.visibility = View.GONE
// group_full_view_items.visibility = View.VISIBLE
headerEmptyViews . forEach { binding . includeHeader . containerHomeHeader . removeView ( it ) }
2018-12-10 08:38:03 -08:00
headerFullViews . forEach {
tryIgnore {
2019-02-14 17:26:56 -08:00
binding . includeHeader . containerHomeHeader . addView ( it )
2018-12-10 08:38:03 -08:00
}
}
2019-01-31 12:44:25 -08:00
}
2018-12-10 08:38:03 -08:00
}
2019-01-31 12:44:25 -08:00
view ?. postDelayed ( {
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 )
2018-12-10 08:38:03 -08:00
}
internal fun toggleValues ( isEmpty : Boolean ) {
empty = isEmpty
if ( empty ) {
reduceValue ( )
} else {
increaseValue ( Random . nextDouble ( 20.0 , 100.0 ) )
}
}
2019-02-14 17:26:56 -08:00
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 ) { }
}
2018-11-12 10:38:37 -08:00
}
2018-12-04 23:26:03 -08:00
@Module
abstract class HomeFragmentModule {
@ContributesAndroidInjector
abstract fun contributeHomeFragment ( ) : HomeFragment
2019-02-14 17:26:56 -08:00
}