multiple sweeping changes.

Presenter injection, main activity nullability and tweaks to twigs
This commit is contained in:
Kevin Gorham 2019-02-21 23:38:06 -05:00 committed by Kevin Gorham
parent 68f674dbf8
commit 8481c7e067
23 changed files with 253 additions and 148 deletions

View File

@ -44,7 +44,7 @@ class AboutFragment : BaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
} }

View File

@ -6,13 +6,15 @@ import dagger.android.support.DaggerFragment
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
abstract class BaseFragment : DaggerFragment(), CoroutineScope { abstract class BaseFragment : DaggerFragment(), CoroutineScope {
private lateinit var job: Job private lateinit var job: Job
val mainActivity get() = activity as MainActivity val mainActivity: MainActivity? get() = activity as MainActivity?
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main

View File

@ -38,10 +38,10 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
postponeEnterTransition() postponeEnterTransition()
binding.buttonNext.setOnClickListener { binding.buttonNext.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_sync_fragment) mainActivity?.navController?.navigate(R.id.nav_sync_fragment)
} }
binding.buttonNext.alpha = 0f // binding.buttonNext.alpha = 0f
binding.textProgressFirstrun.alpha = 0f // binding.textProgressFirstrun.alpha = 0f
} }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -53,8 +53,8 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mainActivity.setDrawerLocked(true) mainActivity?.setDrawerLocked(true)
mainActivity.setToolbarShown(false) mainActivity?.setToolbarShown(false)
} }
private fun setupSharedElementTransitions() { private fun setupSharedElementTransitions() {
@ -69,6 +69,7 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun showProgress(progress: Int) { override fun showProgress(progress: Int) {
super.showProgress(progress) super.showProgress(progress)
binding.textProgressFirstrun.text = getProgressText(progress) binding.textProgressFirstrun.text = getProgressText(progress)
} }
override fun onProgressComplete() { override fun onProgressComplete() {
@ -76,6 +77,10 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
binding.textProgressFirstrun.visibility = View.GONE binding.textProgressFirstrun.visibility = View.GONE
} }
override fun onTransitionStart(transition: Transition) {
binding.buttonNext.alpha = 0f
}
override fun onTransitionEnd(transition: Transition) { override fun onTransitionEnd(transition: Transition) {
binding.buttonNext.animate().apply { binding.buttonNext.animate().apply {
duration = 300L duration = 300L
@ -88,7 +93,6 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun onTransitionResume(transition: Transition) {} override fun onTransitionResume(transition: Transition) {}
override fun onTransitionPause(transition: Transition) {} override fun onTransitionPause(transition: Transition) {}
override fun onTransitionCancel(transition: Transition) {} override fun onTransitionCancel(transition: Transition) {}
override fun onTransitionStart(transition: Transition) {}
} }
@Module @Module

View File

@ -11,17 +11,22 @@ import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentHistoryBinding import cash.z.android.wallet.databinding.FragmentHistoryBinding
import cash.z.android.wallet.ui.adapter.TransactionAdapter import cash.z.android.wallet.ui.adapter.TransactionAdapter
import cash.z.android.wallet.ui.presenter.HistoryPresenter import cash.z.android.wallet.ui.presenter.HistoryPresenter
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
import cash.z.wallet.sdk.dao.WalletTransaction import cash.z.wallet.sdk.dao.WalletTransaction
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView { class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
@Inject
lateinit var historyPresenter: HistoryPresenter lateinit var historyPresenter: HistoryPresenter
lateinit var binding: FragmentHistoryBinding private lateinit var binding: FragmentHistoryBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DataBindingUtil return DataBindingUtil
@ -32,12 +37,13 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) if (mainActivity != null) {
historyPresenter = HistoryPresenter(this, mainActivity.synchronizer) mainActivity?.setToolbarShown(true)
binding.recyclerTransactionsHistory.apply { binding.recyclerTransactionsHistory.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false) layoutManager = LinearLayoutManager(mainActivity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter(R.layout.item_transaction_history) adapter = TransactionAdapter(R.layout.item_transaction_history)
addItemDecoration(AlternatingRowColorDecoration()) addItemDecoration(AlternatingRowColorDecoration())
}
} }
} }
@ -54,7 +60,8 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
} }
override fun setTransactions(transactions: List<WalletTransaction>) { override fun setTransactions(transactions: List<WalletTransaction>) {
mainActivity.supportActionBar?.setTitle(resources.getQuantityString(R.plurals.history_transaction_count_title, transactions.size, transactions.size)) mainActivity?.supportActionBar?.title = resources.getQuantityString(R.plurals.history_transaction_count_title,
transactions.size, transactions.size)
with (binding.recyclerTransactionsHistory) { with (binding.recyclerTransactionsHistory) {
(adapter as TransactionAdapter).submitList(transactions) (adapter as TransactionAdapter).submitList(transactions)
postDelayed({ postDelayed({
@ -68,4 +75,8 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
abstract class HistoryFragmentModule { abstract class HistoryFragmentModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributeHistoryFragment(): HistoryFragment abstract fun contributeHistoryFragment(): HistoryFragment
@Binds
@Singleton
abstract fun providePresenter(historyPresenter: HistoryPresenter): Presenter
} }

View File

@ -23,22 +23,26 @@ import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentHomeBinding import cash.z.android.wallet.databinding.FragmentHomeBinding
import cash.z.android.wallet.extention.* import cash.z.android.wallet.extention.*
import cash.z.android.wallet.sample.SampleProperties import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.ui.activity.MainActivity
import cash.z.android.wallet.ui.adapter.TransactionAdapter import cash.z.android.wallet.ui.adapter.TransactionAdapter
import cash.z.android.wallet.ui.presenter.HomePresenter import cash.z.android.wallet.ui.presenter.HomePresenter
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
import cash.z.android.wallet.ui.util.AnimatorCompleteListener import cash.z.android.wallet.ui.util.AnimatorCompleteListener
import cash.z.android.wallet.ui.util.LottieLooper import cash.z.android.wallet.ui.util.LottieLooper
import cash.z.android.wallet.ui.util.TopAlignedSpan import cash.z.android.wallet.ui.util.TopAlignedSpan
import cash.z.wallet.sdk.dao.WalletTransaction import cash.z.wallet.sdk.dao.WalletTransaction
import cash.z.wallet.sdk.data.ActiveSendTransaction import cash.z.wallet.sdk.data.*
import cash.z.wallet.sdk.data.ActiveTransaction
import cash.z.wallet.sdk.data.TransactionState
import cash.z.wallet.sdk.ext.* import cash.z.wallet.sdk.ext.*
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem import com.leinardi.android.speeddial.SpeedDialActionItem
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.random.Random import kotlin.random.Random
import kotlin.random.nextLong import kotlin.random.nextLong
@ -49,7 +53,9 @@ import kotlin.random.nextLong
*/ */
class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomePresenter.HomeView { class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomePresenter.HomeView {
private lateinit var homePresenter: HomePresenter @Inject
lateinit var homePresenter: HomePresenter
private lateinit var binding: FragmentHomeBinding private lateinit var binding: FragmentHomeBinding
private lateinit var zcashLogoAnimation: LottieLooper private lateinit var zcashLogoAnimation: LottieLooper
private var snackbar: Snackbar? = null private var snackbar: Snackbar? = null
@ -87,19 +93,17 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(false) mainActivity?.setToolbarShown(false)
mainActivity.setDrawerLocked(false) mainActivity?.setDrawerLocked(false)
initFab() initFab()
homePresenter = HomePresenter(this, mainActivity.synchronizer)
binding.includeContent.recyclerTransactions.apply { binding.includeContent.recyclerTransactions.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false) layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter() adapter = TransactionAdapter()
addItemDecoration(AlternatingRowColorDecoration()) addItemDecoration(AlternatingRowColorDecoration())
} }
binding.includeContent.textTransactionHeaderSeeAll.setOnClickListener { binding.includeContent.textTransactionHeaderSeeAll.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_history_fragment) mainActivity?.navController?.navigate(R.id.nav_history_fragment)
} }
} }
@ -130,27 +134,24 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
} }
override fun onRefresh() { override fun onRefresh() {
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from onRefresh") } setRefreshAnimationPlaying(true).also { twig("refresh true from onRefresh") }
with(binding.includeContent.refreshLayout) { with(binding.includeContent.refreshLayout) {
isRefreshing = false isRefreshing = false
val fauxRefresh = Random.nextLong(750L..3000L) val fauxRefresh = Random.nextLong(750L..3000L)
postDelayed({ postDelayed({
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onRefresh") } setRefreshAnimationPlaying(false).also { twig("refresh false from onRefresh") }
}, fauxRefresh) }, fauxRefresh)
} }
} }
fun setRefreshAnimationPlaying(isPlaying: Boolean) { fun setRefreshAnimationPlaying(isPlaying: Boolean) {
Log.e("TWIG-a", "set refresh to: $isPlaying for $zcashLogoAnimation") twig("set refresh to: $isPlaying for $zcashLogoAnimation")
if (isPlaying) { if (isPlaying) {
zcashLogoAnimation.start() zcashLogoAnimation.start()
} else { } else {
zcashLogoAnimation.stop() zcashLogoAnimation.stop()
view?.postDelayed({
zcashLogoAnimation.stop()
}, 500L)
} }
} }
@ -180,12 +181,12 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
private fun onInitialLoadComplete() { private fun onInitialLoadComplete() {
val isEmpty = (binding.includeContent.recyclerTransactions?.adapter?.itemCount ?: 0).let { it == 0 } val isEmpty = (binding.includeContent.recyclerTransactions?.adapter?.itemCount ?: 0).let { it == 0 }
Log.e("TWIG-t", "onInitialLoadComplete and isEmpty == $isEmpty") twig("onInitialLoadComplete and isEmpty == $isEmpty")
setContentViewShown(!isEmpty) setContentViewShown(!isEmpty)
if (isEmpty) { if (isEmpty) {
binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet) binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet)
} }
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onInitialLoadComplete") } setRefreshAnimationPlaying(false).also { twig("refresh false from onInitialLoadComplete") }
} }
@ -208,10 +209,11 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) { private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) {
Log.e("TWIG", "setting transaction state to ${transactionState::class.simpleName}") twig("setting transaction state to ${transactionState::class.simpleName}")
var title = binding.includeContent.textActiveTransactionTitle.text?.toString() ?: "" var title = binding.includeContent.textActiveTransactionTitle.text?.toString() ?: ""
var subtitle = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: "" var subtitle = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: ""
var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE
var isShownDelay = 10L
when (transactionState) { when (transactionState) {
TransactionState.Creating -> { TransactionState.Creating -> {
binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
@ -241,7 +243,8 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
binding.includeContent.textActiveTransactionValue.visibility = View.GONE binding.includeContent.textActiveTransactionValue.visibility = View.GONE
setTransactionActive(transaction, false) setTransactionActive(transaction, false)
setActiveTransactionsShown(false, 10000L) isShown = false
isShownDelay = 10_000L
} }
is TransactionState.AwaitingConfirmations -> { is TransactionState.AwaitingConfirmations -> {
if (transactionState.confirmationCount < 1) { if (transactionState.confirmationCount < 1) {
@ -252,25 +255,32 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
binding.includeContent.textActiveTransactionValue.text = transaction.value.convertZatoshiToZecString(3) binding.includeContent.textActiveTransactionValue.text = transaction.value.convertZatoshiToZecString(3)
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
isShown = true
} else if (transactionState.confirmationCount > 1) { } else if (transactionState.confirmationCount > 1) {
isShown = false isShown = false
} else { } else {
title = "Confirmation Received" title = "Confirmation Received"
subtitle = "Today at 2:12pm" subtitle = "Today at 2:12pm"
isShown = false;
isShownDelay = 5_000L
// take it out of the list in a bit and skip counting confirmation animation for now (i.e. one is enough) // take it out of the list in a bit and skip counting confirmation animation for now (i.e. one is enough)
setActiveTransactionsShown(false, 5000L)
} }
} }
is TransactionState.Cancelled -> { is TransactionState.Cancelled -> {
title = binding.includeContent.textActiveTransactionTitle.text.toString() title = binding.includeContent.textActiveTransactionTitle.text.toString()
subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString() subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
setTransactionActive(transaction, false) setTransactionActive(transaction, false)
setActiveTransactionsShown(false, 10000L) isShown = false
isShownDelay = 10_000L
}
else -> {
Log.e(javaClass.simpleName, "Warning: unrecognized transaction state $transactionState is being ignored")
return
} }
} }
binding.includeContent.textActiveTransactionTitle.text = title binding.includeContent.textActiveTransactionTitle.text = title
binding.includeContent.textActiveTransactionSubtitle.text = subtitle binding.includeContent.textActiveTransactionSubtitle.text = subtitle
setActiveTransactionsShown(isShown) setActiveTransactionsShown(isShown, isShownDelay)
} }
@ -280,9 +290,10 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
private fun setActiveTransactionsShown(isShown: Boolean, delay: Long = 0L) { private fun setActiveTransactionsShown(isShown: Boolean, delay: Long = 0L) {
binding.includeContent.headerActiveTransaction.postDelayed({ binding.includeContent.headerActiveTransaction.postDelayed({
binding.includeContent.headerActiveTransaction.animate().alpha(if(isShown) 1f else 0f).setDuration(250).setListener( // do not animate if visibility is already in the right state
// 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 } AnimatorCompleteListener{ binding.includeContent.groupActiveTransactionItems.visibility = if (isShown) View.VISIBLE else View.GONE }
) // )
}, delay) }, delay)
} }
@ -310,10 +321,9 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
} }
// hide content // hide content
setActiveTransactionsShown(false)
setContentViewShown(false) setContentViewShown(false)
binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet_updating) binding.includeContent.textEmptyWalletMessage.setText(R.string.home_empty_wallet_updating)
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from init") } setRefreshAnimationPlaying(true).also { twig("refresh true from init") }
} }
// initialize the stuff that is temporary and needs to go ASAP // initialize the stuff that is temporary and needs to go ASAP
@ -337,14 +347,14 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
*/ */
private fun initFab() { private fun initFab() {
val speedDial = binding.sdFab val speedDial = binding.sdFab
val nav = mainActivity.navController val nav = mainActivity?.navController
HomeFab.values().forEach { HomeFab.values().forEach {
speedDial.addActionItem(it.createItem()) speedDial.addActionItem(it.createItem())
} }
speedDial.setOnActionSelectedListener { item -> speedDial.setOnActionSelectedListener { item ->
HomeFab.fromId(item.id)?.destination?.apply { nav.navigate(this) } HomeFab.fromId(item.id)?.destination?.apply { nav?.navigate(this) }
false false
} }
} }
@ -394,13 +404,13 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
// situation has changed when we weren't initialized but now we have a balance or emptiness has changed // situation has changed when we weren't initialized but now we have a balance or emptiness has changed
val situationHasChanged = !viewsInitialized || (isEmpty != wasEmpty) val situationHasChanged = !viewsInitialized || (isEmpty != wasEmpty)
Log.e("TWIG-t", "updateEmptyViews called with value: $value initialized: $viewsInitialized isEmpty: $isEmpty wasEmpty: $wasEmpty") twig("updateEmptyViews called with value: $value initialized: $viewsInitialized isEmpty: $isEmpty wasEmpty: $wasEmpty")
if (situationHasChanged) { if (situationHasChanged) {
Log.e("TWIG-t", "The situation has changed! toggling views!") twig("The situation has changed! toggling views!")
setContentViewShown(!isEmpty) setContentViewShown(!isEmpty)
} }
setRefreshAnimationPlaying(false).also { Log.e("TWIG-a", "refresh false from onContentRefreshComplete") } setRefreshAnimationPlaying(false).also { twig("refresh false from onContentRefreshComplete") }
binding.includeHeader.containerHomeHeader.visibility = View.VISIBLE binding.includeHeader.containerHomeHeader.visibility = View.VISIBLE
} }
@ -503,7 +513,7 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
// } // }
internal fun toggleViews(isEmpty: Boolean) { internal fun toggleViews(isEmpty: Boolean) {
Log.e("TWIG-t", "toggling views to isEmpty == $isEmpty") twig("toggling views to isEmpty == $isEmpty")
var action: () -> Unit var action: () -> Unit
if (isEmpty) { if (isEmpty) {
action = { action = {
@ -598,6 +608,10 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
abstract class HomeFragmentModule { abstract class HomeFragmentModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributeHomeFragment(): HomeFragment abstract fun contributeHomeFragment(): HomeFragment
@Binds
@Singleton
abstract fun providePresenter(homePresenter: HomePresenter): Presenter
} }

View File

@ -5,13 +5,19 @@ import android.view.View
import android.widget.ProgressBar import android.widget.ProgressBar
import androidx.annotation.IdRes import androidx.annotation.IdRes
import cash.z.android.wallet.ui.presenter.ProgressPresenter import cash.z.android.wallet.ui.presenter.ProgressPresenter
import cash.z.android.wallet.ui.util.AnimatorCompleteListener import cash.z.wallet.sdk.data.Synchronizer
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFragment(), abstract class ProgressFragment(
@IdRes private val progressBarId: Int
) : BaseFragment(),
ProgressPresenter.ProgressView { ProgressPresenter.ProgressView {
private lateinit var progressPresenter: ProgressPresenter @Inject
protected lateinit var synchronizer: Synchronizer
protected lateinit var progressPresenter: ProgressPresenter
private lateinit var progressBar: ProgressBar private lateinit var progressBar: ProgressBar
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -22,7 +28,7 @@ abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFra
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
progressPresenter = ProgressPresenter(this, mainActivity.synchronizer) progressPresenter = ProgressPresenter(this, synchronizer)
} }
override fun onResume() { override fun onResume() {
@ -40,12 +46,12 @@ abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFra
override fun showProgress(progress: Int) { override fun showProgress(progress: Int) {
if (progress >= 100) { if (progress >= 100) {
onProgressComplete() onProgressComplete()
progressBar.animate().alpha(0.0f).apply { // progressBar.animate().(0.0f).apply {
duration = 250L // duration = 250L
setListener(AnimatorCompleteListener { // setListener(AnimatorCompleteListener {
progressBar.visibility = View.GONE progressBar.visibility = View.GONE
}) // })
} // }
} else if (progress > 0 && progressBar.visibility != View.VISIBLE) { } else if (progress > 0 && progressBar.visibility != View.VISIBLE) {
progressBar.visibility = View.VISIBLE progressBar.visibility = View.VISIBLE
} }
@ -57,9 +63,9 @@ abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFra
open fun getProgressText(progress: Int): String { open fun getProgressText(progress: Int): String {
if (mainActivity == null) return "" if (mainActivity == null) return ""
// cycle twice // cycle twice
val factor = 100 / (mainActivity.loadMessages.size * 2) val factor = 100 / (mainActivity!!.loadMessages.size * 2)
val index = (progress/factor).rem(mainActivity.loadMessages.size) val index = (progress/factor).rem(mainActivity!!.loadMessages.size)
var message = "$progress% ${mainActivity.nextLoadMessage(index)}" var message = "$progress% ${mainActivity?.nextLoadMessage(index)}"
if (progress > 98) message = "Done!" if (progress > 98) message = "Done!"
if (progress >= 50) message = message.replace("Zooko", "Zooko AGAIN", true).replace("Learning to spell", "Double-checking the spelling of").replace("the kool", "MORE kool", true).replace("Making the sausage", "Getting a little hangry by now!", true) if (progress >= 50) message = message.replace("Zooko", "Zooko AGAIN", true).replace("Learning to spell", "Double-checking the spelling of").replace("the kool", "MORE kool", true).replace("Making the sausage", "Getting a little hangry by now!", true)
return message return message

View File

@ -56,7 +56,7 @@ class ReceiveFragment : BaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
} }
override fun onResume() { override fun onResume() {

View File

@ -65,7 +65,7 @@ class RequestFragment : BaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
} }
override fun onDetach() { override fun onDetach() {

View File

@ -65,9 +65,9 @@ class ScanFragment : BaseFragment() {
private val requiredPermissions: Array<String?> private val requiredPermissions: Array<String?>
get() { get() {
return try { return try {
val info = mainActivity.packageManager val info = mainActivity?.packageManager
.getPackageInfo(mainActivity.packageName, PackageManager.GET_PERMISSIONS) ?.getPackageInfo(mainActivity?.packageName, PackageManager.GET_PERMISSIONS)
val ps = info.requestedPermissions val ps = info?.requestedPermissions
if (ps != null && ps.isNotEmpty()) { if (ps != null && ps.isNotEmpty()) {
ps ps
} else { } else {
@ -107,7 +107,7 @@ class ScanFragment : BaseFragment() {
if(!allPermissionsGranted()) getRuntimePermissions() if(!allPermissionsGranted()) getRuntimePermissions()
// sendPresenter = SendPresenter(this, mainActivity.synchronizer) // sendPresenter = SendPresenter(this, mainActivity?.synchronizer)
} }
override fun onResume() { override fun onResume() {
@ -169,7 +169,7 @@ class ScanFragment : BaseFragment() {
private fun allPermissionsGranted(): Boolean { private fun allPermissionsGranted(): Boolean {
for (permission in requiredPermissions) { for (permission in requiredPermissions) {
if (!isPermissionGranted(mainActivity, permission!!)) { if (!isPermissionGranted(mainActivity!!, permission!!)) {
return false return false
} }
} }
@ -179,7 +179,7 @@ class ScanFragment : BaseFragment() {
private fun getRuntimePermissions() { private fun getRuntimePermissions() {
val allNeededPermissions = arrayListOf<String>() val allNeededPermissions = arrayListOf<String>()
for (permission in requiredPermissions) { for (permission in requiredPermissions) {
if (!isPermissionGranted(mainActivity, permission!!)) { if (!isPermissionGranted(mainActivity!!, permission!!)) {
allNeededPermissions.add(permission) allNeededPermissions.add(permission)
} }
} }
@ -216,7 +216,7 @@ class ScanFragment : BaseFragment() {
var cameraId = getBackCameraId() var cameraId = getBackCameraId()
private fun getBackCameraId(): String { private fun getBackCameraId(): String {
val manager = mainActivity.getSystemService(Context.CAMERA_SERVICE) as CameraManager val manager = mainActivity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager
for (cameraId in manager.cameraIdList) { for (cameraId in manager.cameraIdList) {
val characteristics = manager.getCameraCharacteristics(cameraId) val characteristics = manager.getCameraCharacteristics(cameraId)
@ -227,10 +227,12 @@ class ScanFragment : BaseFragment() {
} }
override fun onImageAvailable(image: Image) { override fun onImageAvailable(image: Image) {
if(mainActivity == null) return
try { try {
System.err.println("camoorah : onImageAvailable: $image width: ${image.width} height: ${image.height}") System.err.println("camoorah : onImageAvailable: $image width: ${image.width} height: ${image.height}")
var firebaseImage = var firebaseImage =
FirebaseVisionImage.fromMediaImage(image, getRotationCompensation(cameraId, mainActivity)) FirebaseVisionImage.fromMediaImage(image, getRotationCompensation(cameraId, mainActivity!!))
barcodeDetector barcodeDetector
.detectInImage(firebaseImage) .detectInImage(firebaseImage)
.addOnSuccessListener { results -> .addOnSuccessListener { results ->

View File

@ -23,12 +23,15 @@ import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentSendBinding import cash.z.android.wallet.databinding.FragmentSendBinding
import cash.z.android.wallet.extention.* import cash.z.android.wallet.extention.*
import cash.z.android.wallet.sample.SampleProperties import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.presenter.SendPresenter import cash.z.android.wallet.ui.presenter.SendPresenter
import cash.z.wallet.sdk.ext.convertZatoshiToZecString import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.safelyConvertToBigDecimal import dagger.Binds
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
/** /**
* Fragment for sending Zcash. * Fragment for sending Zcash.
@ -39,8 +42,9 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
private val zec = R.string.zec_abbreviation.toAppString() private val zec = R.string.zec_abbreviation.toAppString()
private val usd = R.string.usd_abbreviation.toAppString() private val usd = R.string.usd_abbreviation.toAppString()
@Inject
lateinit var sendPresenter: SendPresenter lateinit var sendPresenter: SendPresenter
lateinit var binding: FragmentSendBinding private lateinit var binding: FragmentSendBinding
// //
@ -71,8 +75,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
sendPresenter = SendPresenter(this, mainActivity.synchronizer)
} }
override fun onResume() { override fun onResume() {
@ -93,7 +96,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
// //
override fun exit() { override fun exit() {
mainActivity.navController.navigate(R.id.nav_home_fragment) mainActivity?.navController?.navigate(R.id.nav_home_fragment)
} }
override fun setHeaders(isUsdSelected: Boolean, headerString: String, subheaderString: String) { override fun setHeaders(isUsdSelected: Boolean, headerString: String, subheaderString: String) {
@ -280,7 +283,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
} }
private fun hideKeyboard() { private fun hideKeyboard() {
mainActivity.getSystemService<InputMethodManager>() mainActivity?.getSystemService<InputMethodManager>()
?.hideSoftInputFromWindow(view?.windowToken, InputMethodManager.HIDE_NOT_ALWAYS) ?.hideSoftInputFromWindow(view?.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
checkAllInput() checkAllInput()
} }
@ -291,10 +294,12 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
} }
private fun setAddressLineColor(@ColorRes colorRes: Int = R.color.zcashBlack_12) { private fun setAddressLineColor(@ColorRes colorRes: Int = R.color.zcashBlack_12) {
DrawableCompat.setTint( if (mainActivity != null) {
binding.inputZcashAddress.background, DrawableCompat.setTint(
ContextCompat.getColor(mainActivity, colorRes) binding.inputZcashAddress.background,
) ContextCompat.getColor(mainActivity!!, colorRes)
)
}
} }
@ -347,11 +352,9 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
*/ */
override fun checkAllInput(): Boolean { override fun checkAllInput(): Boolean {
with(binding) { with(binding) {
return sendPresenter.validateAll( return sendPresenter.inputHeaderUpdated(textValueHeader.text.toString())
headerValue = textValueHeader.text.toString(), && sendPresenter.inputAddressUpdated(inputZcashAddress.text.toString())
toAddress = inputZcashAddress.text.toString(), && sendPresenter.inputMemoUpdated(textAreaMemo.text.toString())
memo = textAreaMemo.text.toString()
)
} }
} }
@ -371,7 +374,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
// binding.dialogSendBackground to getString(R.string.transition_active_transaction_background) // binding.dialogSendBackground to getString(R.string.transition_active_transaction_background)
// ) // )
// //
// mainActivity.navController.navigate(R.id.nav_home_fragment, // mainActivity?.navController.navigate(R.id.nav_home_fragment,
// null, // null,
// null, // null,
// extras) // extras)
@ -385,4 +388,8 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
abstract class SendFragmentModule { abstract class SendFragmentModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributeSendFragment(): SendFragment abstract fun contributeSendFragment(): SendFragment
@Binds
@Singleton
abstract fun providePresenter(sendPresenter: SendPresenter): Presenter
} }

View File

@ -25,15 +25,15 @@ class SettingsFragment : BaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.buttonResetApp.setOnClickListener { binding.buttonResetApp.setOnClickListener {
view.context.alert(R.string.settings_alert_reset_app) { view.context.alert(R.string.settings_alert_reset_app) {
Toaster.short("Boom") Toaster.short("Not Yet Implemented!")
mainActivity.navController.navigateUp() mainActivity?.navController?.navigateUp()
} }
} }
} }

View File

@ -4,11 +4,19 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.doOnPreDraw
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.transition.TransitionInflater
import cash.z.android.wallet.R import cash.z.android.wallet.R
import cash.z.android.wallet.databinding.FragmentSyncBinding import cash.z.android.wallet.databinding.FragmentSyncBinding
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.presenter.ProgressPresenter
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
class SyncFragment : ProgressFragment(R.id.progress_sync) { class SyncFragment : ProgressFragment(R.id.progress_sync) {
@ -22,6 +30,7 @@ class SyncFragment : ProgressFragment(R.id.progress_sync) {
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
setupSharedElementTransitions()
return DataBindingUtil.inflate<FragmentSyncBinding>( return DataBindingUtil.inflate<FragmentSyncBinding>(
inflater, R.layout.fragment_sync, container, false inflater, R.layout.fragment_sync, container, false
).let { ).let {
@ -32,17 +41,34 @@ class SyncFragment : ProgressFragment(R.id.progress_sync) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
postponeEnterTransition()
binding.buttonNext.setOnClickListener { binding.buttonNext.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_home_fragment) mainActivity?.navController?.navigate(R.id.nav_home_fragment)
} }
binding.progressSync.visibility = View.INVISIBLE binding.progressSync.visibility = View.INVISIBLE
binding.textProgressSync.visibility = View.INVISIBLE binding.textProgressSync.visibility = View.INVISIBLE
} }
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(view?.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mainActivity.setDrawerLocked(true) mainActivity?.setDrawerLocked(true)
mainActivity.setToolbarShown(true) mainActivity?.setToolbarShown(true)
}
private fun setupSharedElementTransitions() {
TransitionInflater.from(mainActivity).inflateTransition(R.transition.transition_zec_sent).apply {
duration = 250L
// addListener(this@SyncFragment)
this@SyncFragment.sharedElementEnterTransition = this
this@SyncFragment.sharedElementReturnTransition = this
}
} }
override fun showProgress(progress: Int) { override fun showProgress(progress: Int) {
@ -69,4 +95,5 @@ abstract class SyncFragmentModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributeSyncFragment(): SyncFragment abstract fun contributeSyncFragment(): SyncFragment
} }

View File

@ -24,15 +24,20 @@ import android.util.Log
import androidx.core.app.SharedElementCallback import androidx.core.app.SharedElementCallback
import androidx.transition.TransitionInflater import androidx.transition.TransitionInflater
import cash.z.android.wallet.BuildConfig import cash.z.android.wallet.BuildConfig
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.presenter.ProgressPresenter import cash.z.android.wallet.ui.presenter.ProgressPresenter
import dagger.Binds
import dagger.BindsInstance
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
class WelcomeFragment : ProgressFragment(R.id.progress_welcome) { class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
private lateinit var binding: FragmentWelcomeBinding private lateinit var binding: FragmentWelcomeBinding
private lateinit var progressPresenter: ProgressPresenter
// //
// Lifecycle // Lifecycle
@ -91,8 +96,8 @@ class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mainActivity.setDrawerLocked(true) mainActivity?.setDrawerLocked(true)
mainActivity.setToolbarShown(false) mainActivity?.setToolbarShown(false)
} }
private fun setupSharedElementTransitions() { private fun setupSharedElementTransitions() {
@ -102,23 +107,25 @@ class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
} }
} }
private suspend fun onNext() = coroutineScope { private suspend fun onNext() = coroutineScope {
val isFirstRun = mainActivity.synchronizer.isFirstRun() if (mainActivity != null) {
val destination = if (isFirstRun) R.id.nav_firstrun_fragment else R.id.nav_sync_fragment val isFirstRun = mainActivity!!.synchronizer.isFirstRun()
val destination = if (isFirstRun) R.id.nav_firstrun_fragment else R.id.nav_sync_fragment
// var extras = with(binding) { // var extras = with(binding) {
// listOf(progressWelcome, textProgressWelcome) // listOf(progressWelcome, textProgressWelcome)
// .map { it to it.transitionName } // .map { it to it.transitionName }
// .let { FragmentNavigatorExtras(*it.toTypedArray()) } // .let { FragmentNavigatorExtras(*it.toTypedArray()) }
// } // }
val extras = FragmentNavigatorExtras( val extras = FragmentNavigatorExtras(
binding.progressWelcome to binding.progressWelcome.transitionName binding.progressWelcome to binding.progressWelcome.transitionName
) )
mainActivity.navController.navigate( mainActivity?.navController?.navigate(
destination, destination,
null, null,
null, null,
extras extras
) )
}
} }
} }
@ -128,4 +135,5 @@ abstract class WelcomeFragmentModule {
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun contributeWelcomeFragment(): WelcomeFragment abstract fun contributeWelcomeFragment(): WelcomeFragment
} }

View File

@ -1,21 +1,22 @@
package cash.z.android.wallet.ui.presenter package cash.z.android.wallet.ui.presenter
import android.util.Log import android.util.Log
import cash.z.android.wallet.ui.fragment.HistoryFragment
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.wallet.sdk.dao.WalletTransaction import cash.z.wallet.sdk.dao.WalletTransaction
import cash.z.wallet.sdk.data.ActiveSendTransaction
import cash.z.wallet.sdk.data.ActiveTransaction
import cash.z.wallet.sdk.data.Synchronizer import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.TransactionState
import cash.z.wallet.sdk.data.twig import cash.z.wallet.sdk.data.twig
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HistoryPresenter( class HistoryPresenter @Inject constructor(
private val view: HistoryView, private val view: HistoryFragment,
private val synchronizer: Synchronizer private var synchronizer: Synchronizer
) : Presenter, CoroutineScope { ) : Presenter, CoroutineScope {
private val job = Job() private val job = Job()

View File

@ -1,6 +1,8 @@
package cash.z.android.wallet.ui.presenter package cash.z.android.wallet.ui.presenter
import android.util.Log import android.util.Log
import cash.z.android.wallet.ZcashWalletApplication
import cash.z.android.wallet.ui.fragment.HomeFragment
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.wallet.sdk.dao.WalletTransaction import cash.z.wallet.sdk.dao.WalletTransaction
import cash.z.wallet.sdk.data.ActiveSendTransaction import cash.z.wallet.sdk.data.ActiveSendTransaction
@ -10,10 +12,11 @@ import cash.z.wallet.sdk.data.TransactionState
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HomePresenter( class HomePresenter @Inject constructor(
private val view: HomeView, private val view: HomeFragment,
private val synchronizer: Synchronizer private val synchronizer: Synchronizer
) : Presenter, CoroutineScope { ) : Presenter, CoroutineScope {

View File

@ -6,11 +6,12 @@ import cash.z.wallet.sdk.data.Twig
import cash.z.wallet.sdk.data.twig import cash.z.wallet.sdk.data.twig
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class ProgressPresenter( class ProgressPresenter @Inject constructor(
private val view: ProgressView, private val view: ProgressView,
private val synchronizer: Synchronizer private var synchronizer: Synchronizer
) : Presenter, CoroutineScope { ) : Presenter, CoroutineScope {
private val job = Job() private val job = Job()
@ -40,7 +41,7 @@ class ProgressPresenter(
for (i in channel) { for (i in channel) {
bind(i) bind(i)
} }
// TODO: remove this temp fix: // "receive" and send 100, whenever the channel is closed for send
bind(100) bind(100)
twig("progress monitor exiting!") twig("progress monitor exiting!")
} }

View File

@ -4,6 +4,7 @@ import cash.z.android.wallet.R
import cash.z.android.wallet.extention.toAppInt import cash.z.android.wallet.extention.toAppInt
import cash.z.android.wallet.extention.toAppString import cash.z.android.wallet.extention.toAppString
import cash.z.android.wallet.sample.SampleProperties import cash.z.android.wallet.sample.SampleProperties
import cash.z.android.wallet.ui.fragment.SendFragment
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
import cash.z.wallet.sdk.data.Synchronizer import cash.z.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.twig import cash.z.wallet.sdk.data.twig
@ -15,9 +16,10 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.math.BigDecimal import java.math.BigDecimal
import javax.inject.Inject
class SendPresenter( class SendPresenter @Inject constructor(
private val view: SendView, private val view: SendFragment,
private val synchronizer: Synchronizer private val synchronizer: Synchronizer
) : Presenter { ) : Presenter {
@ -89,6 +91,8 @@ class SendPresenter(
//TODO: prehaps grab the activity scope or let the sycnchronizer have scope and make that function not suspend //TODO: prehaps grab the activity scope or let the sycnchronizer have scope and make that function not suspend
// also, we need to handle cancellations. So yeah, definitely do this differently // also, we need to handle cancellations. So yeah, definitely do this differently
GlobalScope.launch { GlobalScope.launch {
twig("Process: cash.z.android.wallet. checking....")
twig("Process: cash.z.android.wallet. is it null??? $sendUiModel")
synchronizer.sendToAddress(sendUiModel.zatoshiValue!!, sendUiModel.toAddress) synchronizer.sendToAddress(sendUiModel.zatoshiValue!!, sendUiModel.toAddress)
} }
view.exit() view.exit()
@ -156,8 +160,8 @@ class SendPresenter(
/** /**
* Called when the user has completed their update to the header value, typically on focus change. * Called when the user has completed their update to the header value, typically on focus change.
*/ */
fun inputHeaderUpdated(amountString: String) { fun inputHeaderUpdated(amountString: String): Boolean {
if (!validateAmount(amountString)) return if (!validateAmount(amountString)) return false
// either USD or ZEC -- TODO: use strong typing (and polymorphism) instead of isUsdSelected checks // either USD or ZEC -- TODO: use strong typing (and polymorphism) instead of isUsdSelected checks
val amount = amountString.safelyConvertToBigDecimal()!! // we've already validated this as not null and it's immutable val amount = amountString.safelyConvertToBigDecimal()!! // we've already validated this as not null and it's immutable
@ -179,20 +183,24 @@ class SendPresenter(
view.setHeaders(sendUiModel.isUsdSelected, headerString, subheaderString) view.setHeaders(sendUiModel.isUsdSelected, headerString, subheaderString)
} }
} }
return true
} }
fun inputAddressUpdated(newAddress: String) { fun inputAddressUpdated(newAddress: String): Boolean {
if (!validateAddress(newAddress)) return if (!validateAddress(newAddress)) return false
updateModel(sendUiModel.copy(toAddress = newAddress)) updateModel(sendUiModel.copy(toAddress = newAddress))
return true
} }
fun inputMemoUpdated(newMemo: String) { fun inputMemoUpdated(newMemo: String): Boolean {
if (!validateMemo(newMemo)) return if (!validateMemo(newMemo)) return false
updateModel(sendUiModel.copy(memo = newMemo)) updateModel(sendUiModel.copy(memo = newMemo))
return true
} }
fun inputSendPressed() { fun inputSendPressed(): Boolean {
if (requiresValidation && !view.checkAllInput()) return // double sanity check. Make sure view and model agree and are each valid and if not, highlight the error.
if (!view.checkAllInput() || !validateAll()) return false
with(sendUiModel) { with(sendUiModel) {
view.showSendDialog( view.showSendDialog(
@ -202,6 +210,7 @@ class SendPresenter(
hasMemo = !memo.isBlank() hasMemo = !memo.isBlank()
) )
} }
return true
} }
fun bind(newZecBalance: Long) { fun bind(newZecBalance: Long) {
@ -214,7 +223,7 @@ class SendPresenter(
fun updateModel(newModel: SendUiModel) { fun updateModel(newModel: SendUiModel) {
sendUiModel = newModel.apply { hasBeenUpdated = true } sendUiModel = newModel.apply { hasBeenUpdated = true }
// now that we have new data, check and see if we can clear errors and re-enable the send button // now that we have new data, check and see if we can clear errors and re-enable the send button
if (requiresValidation) view.checkAllInput() if (requiresValidation) validateAll()
} }
// //
@ -310,13 +319,15 @@ class SendPresenter(
} }
} }
fun validateAll(headerValue: String, toAddress: String, memo: String): Boolean { fun validateAll(): Boolean {
val isValid = validateAmount(headerValue) with(sendUiModel) {
&& validateAddress(toAddress) val isValid = validateZatoshiAmount(zatoshiValue)
&& validateMemo(memo) && validateAddress(toAddress)
requiresValidation = !isValid && validateMemo(memo)
view.setSendEnabled(isValid) requiresValidation = !isValid
return isValid view.setSendEnabled(isValid)
return isValid
}
} }

View File

@ -19,6 +19,7 @@ class LottieLooper(private val lottie: LottieAnimationView, private val loopRang
if (isPlaying) return if (isPlaying) return
with(lottie) { with(lottie) {
setMinAndMaxFrame(1, loopRange.last) setMinAndMaxFrame(1, loopRange.last)
progress = 0f
repeatCount = 0 repeatCount = 0
addAnimatorListener(this@LottieLooper) addAnimatorListener(this@LottieLooper)
playAnimation() playAnimation()
@ -78,7 +79,7 @@ class LottieLooper(private val lottie: LottieAnimationView, private val loopRang
lottie.pauseAnimation() lottie.pauseAnimation()
lottie.setMinAndMaxFrame(lastFrame, lastFrame) lottie.setMinAndMaxFrame(lastFrame, lastFrame)
lottie.progress = 1.0f lottie.progress = 1.0f
// wait around a bit to see if there's any movement, then quietly make my getaway // wait around a bit to see if my listeners detect any movement, then quietly make my getaway
lottie.postDelayed({ lottie.postDelayed({
lottie.removeAnimatorListener(this) lottie.removeAnimatorListener(this)
lottie.setMinAndMaxFrame(1, lastFrame) lottie.setMinAndMaxFrame(1, lastFrame)

View File

@ -54,7 +54,6 @@
android:paddingRight="8dp" android:paddingRight="8dp"
android:paddingBottom="16dp" android:paddingBottom="16dp"
android:transitionName="@string/transition_active_transaction_card" android:transitionName="@string/transition_active_transaction_card"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_active_transaction_header" app:layout_constraintTop_toBottomOf="@id/text_active_transaction_header"
tools:visibility="visible"> tools:visibility="visible">
@ -206,6 +205,7 @@
android:id="@+id/group_active_transaction_items" android:id="@+id/group_active_transaction_items"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="text_active_transaction_header,header_active_transaction" /> app:constraint_referenced_ids="text_active_transaction_header,header_active_transaction" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group

View File

@ -0,0 +1,5 @@
{
"height": 421720,
"time": 1550762014,
"tree": "015495a30aef9e18b9c774df6a9fcd583748c8bba1a6348e70f59bc9f0c2bc673b000f00000000018054b75173b577dc36f2c80dfc41f83d6716557597f74ec54436df32d4466d57000120f1825067a52ca973b07431199d5866a0d46ef231d08aa2f544665936d5b4520168d782e3d028131f59e9296c75de5a101898c5e53108e45baa223c608d6c3d3d01fb0a8d465b57c15d793c742df9470b116ddf06bd30d42123fdb7becef1fd63640001a86b141bdb55fd5f5b2e880ea4e07caf2bbf1ac7b52a9f504977913068a917270001dd960b6c11b157d1626f0768ec099af9385aea3f31c91111a8c5b899ffb99e6b0192acd61b1853311b0bf166057ca433e231c93ab5988844a09a91c113ebc58e18019fbfd76ad6d98cafa0174391546e7022afe62e870e20e16d57c4c419a5c2bb69"
}

View File

@ -16,9 +16,10 @@ import javax.inject.Singleton
internal object SynchronizerModule { internal object SynchronizerModule {
const val MOCK_LOAD_DURATION = 3_000L const val MOCK_LOAD_DURATION = 3_000L
// const val MOCK_LOAD_DURATION = 30_000L // const val MOCK_LOAD_DURATION = 12_000L
const val MOCK_TX_INTERVAL = 20_000L const val MOCK_TX_INTERVAL = 20_000L
const val MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL = 5_000L const val MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL = 4_000L
const val MOCK_IS_FIRST_RUN: Boolean = true
@JvmStatic @JvmStatic
@ -29,6 +30,7 @@ internal object SynchronizerModule {
return SampleQrScanner() return SampleQrScanner()
} }
@JvmStatic @JvmStatic
@Provides @Provides
@Singleton @Singleton
@ -37,7 +39,7 @@ internal object SynchronizerModule {
transactionInterval = MOCK_TX_INTERVAL, transactionInterval = MOCK_TX_INTERVAL,
initialLoadDuration = MOCK_LOAD_DURATION, initialLoadDuration = MOCK_LOAD_DURATION,
activeTransactionUpdateFrequency = MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL, activeTransactionUpdateFrequency = MOCK_ACTIVE_TX_STATE_CHANGE_INTERVAL,
isFirstRun = true isFirstRun = MOCK_IS_FIRST_RUN
) )
} }
} }

View File

@ -49,7 +49,7 @@ buildscript {
'speeddial': 'com.leinardi.android:speed-dial:2.0.0', 'speeddial': 'com.leinardi.android:speed-dial:2.0.0',
'stetho': 'com.facebook.stetho:stetho:1.5.0', 'stetho': 'com.facebook.stetho:stetho:1.5.0',
'zcash': [ 'zcash': [
'walletSdk': "cash.z.android.wallet:zcash-android-wallet-sdk:1.7.1@aar" 'walletSdk': "cash.z.android.wallet:zcash-android-wallet-sdk:1.7.2@aar"
] ]
] ]
repositories { repositories {