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?) {
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.Dispatchers
import kotlinx.coroutines.Job
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext
abstract class BaseFragment : DaggerFragment(), CoroutineScope {
private lateinit var job: Job
val mainActivity get() = activity as MainActivity
val mainActivity: MainActivity? get() = activity as MainActivity?
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main

View File

@ -38,10 +38,10 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
super.onViewCreated(view, savedInstanceState)
postponeEnterTransition()
binding.buttonNext.setOnClickListener {
mainActivity.navController.navigate(R.id.nav_sync_fragment)
mainActivity?.navController?.navigate(R.id.nav_sync_fragment)
}
binding.buttonNext.alpha = 0f
binding.textProgressFirstrun.alpha = 0f
// binding.buttonNext.alpha = 0f
// binding.textProgressFirstrun.alpha = 0f
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -53,8 +53,8 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(false)
mainActivity?.setDrawerLocked(true)
mainActivity?.setToolbarShown(false)
}
private fun setupSharedElementTransitions() {
@ -69,6 +69,7 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun showProgress(progress: Int) {
super.showProgress(progress)
binding.textProgressFirstrun.text = getProgressText(progress)
}
override fun onProgressComplete() {
@ -76,6 +77,10 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
binding.textProgressFirstrun.visibility = View.GONE
}
override fun onTransitionStart(transition: Transition) {
binding.buttonNext.alpha = 0f
}
override fun onTransitionEnd(transition: Transition) {
binding.buttonNext.animate().apply {
duration = 300L
@ -88,7 +93,6 @@ class FirstrunFragment : ProgressFragment(R.id.progress_firstrun), Transition.Tr
override fun onTransitionResume(transition: Transition) {}
override fun onTransitionPause(transition: Transition) {}
override fun onTransitionCancel(transition: Transition) {}
override fun onTransitionStart(transition: Transition) {}
}
@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.ui.adapter.TransactionAdapter
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.wallet.sdk.dao.WalletTransaction
import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
@Inject
lateinit var historyPresenter: HistoryPresenter
lateinit var binding: FragmentHistoryBinding
private lateinit var binding: FragmentHistoryBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return DataBindingUtil
@ -32,12 +37,13 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true)
historyPresenter = HistoryPresenter(this, mainActivity.synchronizer)
binding.recyclerTransactionsHistory.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter(R.layout.item_transaction_history)
addItemDecoration(AlternatingRowColorDecoration())
if (mainActivity != null) {
mainActivity?.setToolbarShown(true)
binding.recyclerTransactionsHistory.apply {
layoutManager = LinearLayoutManager(mainActivity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter(R.layout.item_transaction_history)
addItemDecoration(AlternatingRowColorDecoration())
}
}
}
@ -54,7 +60,8 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
}
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) {
(adapter as TransactionAdapter).submitList(transactions)
postDelayed({
@ -68,4 +75,8 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
abstract class HistoryFragmentModule {
@ContributesAndroidInjector
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.extention.*
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.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.AnimatorCompleteListener
import cash.z.android.wallet.ui.util.LottieLooper
import cash.z.android.wallet.ui.util.TopAlignedSpan
import cash.z.wallet.sdk.dao.WalletTransaction
import cash.z.wallet.sdk.data.ActiveSendTransaction
import cash.z.wallet.sdk.data.ActiveTransaction
import cash.z.wallet.sdk.data.TransactionState
import cash.z.wallet.sdk.data.*
import cash.z.wallet.sdk.ext.*
import com.google.android.material.snackbar.Snackbar
import com.leinardi.android.speeddial.SpeedDialActionItem
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.random.Random
import kotlin.random.nextLong
@ -49,7 +53,9 @@ import kotlin.random.nextLong
*/
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 zcashLogoAnimation: LottieLooper
private var snackbar: Snackbar? = null
@ -87,19 +93,17 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(false)
mainActivity.setDrawerLocked(false)
mainActivity?.setToolbarShown(false)
mainActivity?.setDrawerLocked(false)
initFab()
homePresenter = HomePresenter(this, mainActivity.synchronizer)
binding.includeContent.recyclerTransactions.apply {
layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
adapter = TransactionAdapter()
addItemDecoration(AlternatingRowColorDecoration())
}
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() {
setRefreshAnimationPlaying(true).also { Log.e("TWIG-a", "refresh true from onRefresh") }
setRefreshAnimationPlaying(true).also { twig("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") }
setRefreshAnimationPlaying(false).also { twig("refresh false from onRefresh") }
}, fauxRefresh)
}
}
fun setRefreshAnimationPlaying(isPlaying: Boolean) {
Log.e("TWIG-a", "set refresh to: $isPlaying for $zcashLogoAnimation")
twig("set refresh to: $isPlaying for $zcashLogoAnimation")
if (isPlaying) {
zcashLogoAnimation.start()
} else {
zcashLogoAnimation.stop()
view?.postDelayed({
zcashLogoAnimation.stop()
}, 500L)
}
}
@ -180,12 +181,12 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
private fun onInitialLoadComplete() {
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)
if (isEmpty) {
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) {
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 subtitle = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: ""
var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE
var isShownDelay = 10L
when (transactionState) {
TransactionState.Creating -> {
binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
@ -241,7 +243,8 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
binding.includeContent.textActiveTransactionValue.visibility = View.GONE
setTransactionActive(transaction, false)
setActiveTransactionsShown(false, 10000L)
isShown = false
isShownDelay = 10_000L
}
is TransactionState.AwaitingConfirmations -> {
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.visibility = View.VISIBLE
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
isShown = true
} else if (transactionState.confirmationCount > 1) {
isShown = false
} else {
title = "Confirmation Received"
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)
setActiveTransactionsShown(false, 5000L)
}
}
is TransactionState.Cancelled -> {
title = binding.includeContent.textActiveTransactionTitle.text.toString()
subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
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.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) {
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 }
)
// )
}, delay)
}
@ -310,10 +321,9 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
}
// 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") }
setRefreshAnimationPlaying(true).also { twig("refresh true from init") }
}
// initialize the stuff that is temporary and needs to go ASAP
@ -337,14 +347,14 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
*/
private fun initFab() {
val speedDial = binding.sdFab
val nav = mainActivity.navController
val nav = mainActivity?.navController
HomeFab.values().forEach {
speedDial.addActionItem(it.createItem())
}
speedDial.setOnActionSelectedListener { item ->
HomeFab.fromId(item.id)?.destination?.apply { nav.navigate(this) }
HomeFab.fromId(item.id)?.destination?.apply { nav?.navigate(this) }
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
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) {
Log.e("TWIG-t", "The situation has changed! toggling views!")
twig("The situation has changed! toggling views!")
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
}
@ -503,7 +513,7 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
// }
internal fun toggleViews(isEmpty: Boolean) {
Log.e("TWIG-t", "toggling views to isEmpty == $isEmpty")
twig("toggling views to isEmpty == $isEmpty")
var action: () -> Unit
if (isEmpty) {
action = {
@ -598,6 +608,10 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
abstract class HomeFragmentModule {
@ContributesAndroidInjector
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 androidx.annotation.IdRes
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 javax.inject.Inject
abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFragment(),
abstract class ProgressFragment(
@IdRes private val progressBarId: Int
) : BaseFragment(),
ProgressPresenter.ProgressView {
private lateinit var progressPresenter: ProgressPresenter
@Inject
protected lateinit var synchronizer: Synchronizer
protected lateinit var progressPresenter: ProgressPresenter
private lateinit var progressBar: ProgressBar
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?) {
super.onActivityCreated(savedInstanceState)
progressPresenter = ProgressPresenter(this, mainActivity.synchronizer)
progressPresenter = ProgressPresenter(this, synchronizer)
}
override fun onResume() {
@ -40,12 +46,12 @@ abstract class ProgressFragment(@IdRes private val progressBarId: Int) : BaseFra
override fun showProgress(progress: Int) {
if (progress >= 100) {
onProgressComplete()
progressBar.animate().alpha(0.0f).apply {
duration = 250L
setListener(AnimatorCompleteListener {
// progressBar.animate().(0.0f).apply {
// duration = 250L
// setListener(AnimatorCompleteListener {
progressBar.visibility = View.GONE
})
}
// })
// }
} else if (progress > 0 && 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 {
if (mainActivity == null) return ""
// cycle twice
val factor = 100 / (mainActivity.loadMessages.size * 2)
val index = (progress/factor).rem(mainActivity.loadMessages.size)
var message = "$progress% ${mainActivity.nextLoadMessage(index)}"
val factor = 100 / (mainActivity!!.loadMessages.size * 2)
val index = (progress/factor).rem(mainActivity!!.loadMessages.size)
var message = "$progress% ${mainActivity?.nextLoadMessage(index)}"
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)
return message

View File

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

View File

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

View File

@ -65,9 +65,9 @@ class ScanFragment : BaseFragment() {
private val requiredPermissions: Array<String?>
get() {
return try {
val info = mainActivity.packageManager
.getPackageInfo(mainActivity.packageName, PackageManager.GET_PERMISSIONS)
val ps = info.requestedPermissions
val info = mainActivity?.packageManager
?.getPackageInfo(mainActivity?.packageName, PackageManager.GET_PERMISSIONS)
val ps = info?.requestedPermissions
if (ps != null && ps.isNotEmpty()) {
ps
} else {
@ -107,7 +107,7 @@ class ScanFragment : BaseFragment() {
if(!allPermissionsGranted()) getRuntimePermissions()
// sendPresenter = SendPresenter(this, mainActivity.synchronizer)
// sendPresenter = SendPresenter(this, mainActivity?.synchronizer)
}
override fun onResume() {
@ -169,7 +169,7 @@ class ScanFragment : BaseFragment() {
private fun allPermissionsGranted(): Boolean {
for (permission in requiredPermissions) {
if (!isPermissionGranted(mainActivity, permission!!)) {
if (!isPermissionGranted(mainActivity!!, permission!!)) {
return false
}
}
@ -179,7 +179,7 @@ class ScanFragment : BaseFragment() {
private fun getRuntimePermissions() {
val allNeededPermissions = arrayListOf<String>()
for (permission in requiredPermissions) {
if (!isPermissionGranted(mainActivity, permission!!)) {
if (!isPermissionGranted(mainActivity!!, permission!!)) {
allNeededPermissions.add(permission)
}
}
@ -216,7 +216,7 @@ class ScanFragment : BaseFragment() {
var cameraId = getBackCameraId()
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) {
val characteristics = manager.getCameraCharacteristics(cameraId)
@ -227,10 +227,12 @@ class ScanFragment : BaseFragment() {
}
override fun onImageAvailable(image: Image) {
if(mainActivity == null) return
try {
System.err.println("camoorah : onImageAvailable: $image width: ${image.width} height: ${image.height}")
var firebaseImage =
FirebaseVisionImage.fromMediaImage(image, getRotationCompensation(cameraId, mainActivity))
FirebaseVisionImage.fromMediaImage(image, getRotationCompensation(cameraId, mainActivity!!))
barcodeDetector
.detectInImage(firebaseImage)
.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.extention.*
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.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.safelyConvertToBigDecimal
import dagger.Binds
import dagger.Module
import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
/**
* 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 usd = R.string.usd_abbreviation.toAppString()
@Inject
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?) {
super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true)
sendPresenter = SendPresenter(this, mainActivity.synchronizer)
mainActivity?.setToolbarShown(true)
}
override fun onResume() {
@ -93,7 +96,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
//
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) {
@ -280,7 +283,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
}
private fun hideKeyboard() {
mainActivity.getSystemService<InputMethodManager>()
mainActivity?.getSystemService<InputMethodManager>()
?.hideSoftInputFromWindow(view?.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
checkAllInput()
}
@ -291,10 +294,12 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
}
private fun setAddressLineColor(@ColorRes colorRes: Int = R.color.zcashBlack_12) {
DrawableCompat.setTint(
binding.inputZcashAddress.background,
ContextCompat.getColor(mainActivity, colorRes)
)
if (mainActivity != null) {
DrawableCompat.setTint(
binding.inputZcashAddress.background,
ContextCompat.getColor(mainActivity!!, colorRes)
)
}
}
@ -347,11 +352,9 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
*/
override fun checkAllInput(): Boolean {
with(binding) {
return sendPresenter.validateAll(
headerValue = textValueHeader.text.toString(),
toAddress = inputZcashAddress.text.toString(),
memo = textAreaMemo.text.toString()
)
return sendPresenter.inputHeaderUpdated(textValueHeader.text.toString())
&& sendPresenter.inputAddressUpdated(inputZcashAddress.text.toString())
&& sendPresenter.inputMemoUpdated(textAreaMemo.text.toString())
}
}
@ -371,7 +374,7 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
// 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,
// extras)
@ -385,4 +388,8 @@ class SendFragment : BaseFragment(), SendPresenter.SendView, ScanFragment.Barcod
abstract class SendFragmentModule {
@ContributesAndroidInjector
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?) {
super.onActivityCreated(savedInstanceState)
mainActivity.setToolbarShown(true)
mainActivity?.setToolbarShown(true)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonResetApp.setOnClickListener {
view.context.alert(R.string.settings_alert_reset_app) {
Toaster.short("Boom")
mainActivity.navController.navigateUp()
Toaster.short("Not Yet Implemented!")
mainActivity?.navController?.navigateUp()
}
}
}

View File

@ -4,11 +4,19 @@ 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.TransitionInflater
import cash.z.android.wallet.R
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.android.ContributesAndroidInjector
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
class SyncFragment : ProgressFragment(R.id.progress_sync) {
@ -22,6 +30,7 @@ class SyncFragment : ProgressFragment(R.id.progress_sync) {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setupSharedElementTransitions()
return DataBindingUtil.inflate<FragmentSyncBinding>(
inflater, R.layout.fragment_sync, container, false
).let {
@ -32,17 +41,34 @@ class SyncFragment : ProgressFragment(R.id.progress_sync) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
postponeEnterTransition()
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.textProgressSync.visibility = View.INVISIBLE
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(view?.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
}
}
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(true)
mainActivity?.setDrawerLocked(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) {
@ -69,4 +95,5 @@ abstract class SyncFragmentModule {
@ContributesAndroidInjector
abstract fun contributeSyncFragment(): SyncFragment
}

View File

@ -24,15 +24,20 @@ import android.util.Log
import androidx.core.app.SharedElementCallback
import androidx.transition.TransitionInflater
import cash.z.android.wallet.BuildConfig
import cash.z.android.wallet.ui.presenter.Presenter
import cash.z.android.wallet.ui.presenter.ProgressPresenter
import dagger.Binds
import dagger.BindsInstance
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
private lateinit var binding: FragmentWelcomeBinding
private lateinit var progressPresenter: ProgressPresenter
//
// Lifecycle
@ -91,8 +96,8 @@ class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
override fun onResume() {
super.onResume()
mainActivity.setDrawerLocked(true)
mainActivity.setToolbarShown(false)
mainActivity?.setDrawerLocked(true)
mainActivity?.setToolbarShown(false)
}
private fun setupSharedElementTransitions() {
@ -102,23 +107,25 @@ class WelcomeFragment : ProgressFragment(R.id.progress_welcome) {
}
}
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
if (mainActivity != null) {
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
)
// 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
)
}
}
}
@ -128,4 +135,5 @@ abstract class WelcomeFragmentModule {
@ContributesAndroidInjector
abstract fun contributeWelcomeFragment(): WelcomeFragment
}

View File

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

View File

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

View File

@ -6,11 +6,12 @@ import cash.z.wallet.sdk.data.Twig
import cash.z.wallet.sdk.data.twig
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
class ProgressPresenter(
class ProgressPresenter @Inject constructor(
private val view: ProgressView,
private val synchronizer: Synchronizer
private var synchronizer: Synchronizer
) : Presenter, CoroutineScope {
private val job = Job()
@ -40,7 +41,7 @@ class ProgressPresenter(
for (i in channel) {
bind(i)
}
// TODO: remove this temp fix:
// "receive" and send 100, whenever the channel is closed for send
bind(100)
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.toAppString
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.wallet.sdk.data.Synchronizer
import cash.z.wallet.sdk.data.twig
@ -15,9 +16,10 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
class SendPresenter(
private val view: SendView,
class SendPresenter @Inject constructor(
private val view: SendFragment,
private val synchronizer: Synchronizer
) : 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
// also, we need to handle cancellations. So yeah, definitely do this differently
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)
}
view.exit()
@ -156,8 +160,8 @@ class SendPresenter(
/**
* Called when the user has completed their update to the header value, typically on focus change.
*/
fun inputHeaderUpdated(amountString: String) {
if (!validateAmount(amountString)) return
fun inputHeaderUpdated(amountString: String): Boolean {
if (!validateAmount(amountString)) return false
// 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
@ -179,20 +183,24 @@ class SendPresenter(
view.setHeaders(sendUiModel.isUsdSelected, headerString, subheaderString)
}
}
return true
}
fun inputAddressUpdated(newAddress: String) {
if (!validateAddress(newAddress)) return
fun inputAddressUpdated(newAddress: String): Boolean {
if (!validateAddress(newAddress)) return false
updateModel(sendUiModel.copy(toAddress = newAddress))
return true
}
fun inputMemoUpdated(newMemo: String) {
if (!validateMemo(newMemo)) return
fun inputMemoUpdated(newMemo: String): Boolean {
if (!validateMemo(newMemo)) return false
updateModel(sendUiModel.copy(memo = newMemo))
return true
}
fun inputSendPressed() {
if (requiresValidation && !view.checkAllInput()) return
fun inputSendPressed(): Boolean {
// 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) {
view.showSendDialog(
@ -202,6 +210,7 @@ class SendPresenter(
hasMemo = !memo.isBlank()
)
}
return true
}
fun bind(newZecBalance: Long) {
@ -214,7 +223,7 @@ class SendPresenter(
fun updateModel(newModel: SendUiModel) {
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
if (requiresValidation) view.checkAllInput()
if (requiresValidation) validateAll()
}
//
@ -310,13 +319,15 @@ class SendPresenter(
}
}
fun validateAll(headerValue: String, toAddress: String, memo: String): Boolean {
val isValid = validateAmount(headerValue)
&& validateAddress(toAddress)
&& validateMemo(memo)
requiresValidation = !isValid
view.setSendEnabled(isValid)
return isValid
fun validateAll(): Boolean {
with(sendUiModel) {
val isValid = validateZatoshiAmount(zatoshiValue)
&& validateAddress(toAddress)
&& validateMemo(memo)
requiresValidation = !isValid
view.setSendEnabled(isValid)
return isValid
}
}

View File

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

View File

@ -54,7 +54,6 @@
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">
@ -206,6 +205,7 @@
android:id="@+id/group_active_transaction_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="text_active_transaction_header,header_active_transaction" />
<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 {
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_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
@ -29,6 +30,7 @@ internal object SynchronizerModule {
return SampleQrScanner()
}
@JvmStatic
@Provides
@Singleton
@ -37,7 +39,7 @@ internal object SynchronizerModule {
transactionInterval = MOCK_TX_INTERVAL,
initialLoadDuration = MOCK_LOAD_DURATION,
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',
'stetho': 'com.facebook.stetho:stetho:1.5.0',
'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 {