Improved back navigation flow and animations.

Addresses #61
This commit is contained in:
Kevin Gorham 2020-01-09 11:00:20 -05:00
parent 6ab46f75bb
commit 4c8adf5180
No known key found for this signature in database
GPG Key ID: CCA55602DF49FC38
13 changed files with 133 additions and 33 deletions

View File

@ -13,8 +13,10 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.findNavController
@ -149,7 +151,7 @@ class MainActivity : AppCompatActivity() {
}
}
fun copyAddress(view: View) {
fun copyAddress(view: View? = null) {
lifecycleScope.launch {
clipboard.setPrimaryClip(
ClipData.newPlainText(
@ -161,6 +163,18 @@ class MainActivity : AppCompatActivity() {
}
}
fun preventBackPress(fragment: Fragment) {
onFragmentBackPressed(fragment){}
}
fun onFragmentBackPressed(fragment: Fragment, block: () -> Unit) {
onBackPressedDispatcher.addCallback(fragment, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
block()
}
})
}
private fun showMessage(message: String, action: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

View File

@ -9,10 +9,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import cash.z.ecc.android.ui.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.*
abstract class BaseFragment<T : ViewBinding> : Fragment() {
val mainActivity: MainActivity? get() = activity as MainActivity?
@ -33,7 +30,7 @@ abstract class BaseFragment<T : ViewBinding> : Fragment() {
override fun onResume() {
super.onResume()
resumedScope = lifecycleScope.coroutineContext.let {
CoroutineScope(it + SupervisorJob(it[Job]))
CoroutineScope(Dispatchers.Main + SupervisorJob(it[Job]))
}
}
@ -45,4 +42,10 @@ abstract class BaseFragment<T : ViewBinding> : Fragment() {
// inflate is static in the ViewBinding class so we can't handle this ourselves
// each fragment must call FragmentMyLayoutBinding.inflate(inflater)
abstract fun inflate(@NonNull inflater: LayoutInflater): T
fun onBackPressNavTo(navResId: Int) {
mainActivity?.onFragmentBackPressed(this) {
mainActivity?.navController?.navigate(navResId)
}
}
}

View File

@ -13,9 +13,6 @@ import cash.z.ecc.android.ext.*
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onErrorResumeNext
import kotlinx.coroutines.launch
class SendAddressFragment : BaseFragment<FragmentSendAddressBinding>(),
@ -31,7 +28,7 @@ class SendAddressFragment : BaseFragment<FragmentSendAddressBinding>(),
binding.buttonNext.setOnClickListener {
onSubmit()
}
binding.backButtonHitArea.onClickNavBack()
binding.backButtonHitArea.onClickNavTo(R.id.action_nav_send_address_to_nav_home)
binding.textBannerAction.setOnClickListener {
onPaste()
}
@ -49,7 +46,7 @@ class SendAddressFragment : BaseFragment<FragmentSendAddressBinding>(),
binding.inputZcashAmount.setText(null)
}
if (!sendViewModel.toAddress.isNullOrEmpty()){
binding.textAmount.text = "Send to ${sendViewModel.toAddress.abbreviatedAddress()}"
binding.textAmount.text = "Send to ${sendViewModel.toAddress.toAbbreviatedAddress()}"
binding.inputZcashAddress.setText(sendViewModel.toAddress)
} else {
binding.inputZcashAddress.setText(null)

View File

@ -7,11 +7,11 @@ import androidx.lifecycle.lifecycleScope
import cash.z.ecc.android.R
import cash.z.ecc.android.databinding.FragmentSendConfirmBinding
import cash.z.ecc.android.di.viewmodel.activityViewModel
import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.ext.goneIf
import cash.z.ecc.android.ext.onClickNavBack
import cash.z.ecc.android.ext.onClickNavTo
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.ext.abbreviatedAddress
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import kotlinx.coroutines.launch
@ -27,10 +27,13 @@ class SendConfirmFragment : BaseFragment<FragmentSendConfirmBinding>() {
binding.buttonNext.setOnClickListener {
onSend()
}
binding.backButtonHitArea.onClickNavBack()
R.id.action_nav_send_confirm_to_nav_send_memo.let {
binding.backButtonHitArea.onClickNavTo(it)
onBackPressNavTo(it)
}
mainActivity?.lifecycleScope?.launch {
binding.textConfirmation.text =
"Send ${sendViewModel.zatoshiAmount.convertZatoshiToZecString(8)} ZEC to ${sendViewModel?.toAddress.abbreviatedAddress()}?"
"Send ${sendViewModel.zatoshiAmount.convertZatoshiToZecString(8)} ZEC to ${sendViewModel?.toAddress.toAbbreviatedAddress()}?"
}
sendViewModel.memo.trim().isNotEmpty().let { hasMemo ->
binding.radioIncludeAddress.isChecked = hasMemo

View File

@ -8,11 +8,10 @@ import androidx.lifecycle.lifecycleScope
import cash.z.ecc.android.R
import cash.z.ecc.android.databinding.FragmentSendFinalBinding
import cash.z.ecc.android.di.viewmodel.activityViewModel
import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.ext.goneIf
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.entity.*
import cash.z.wallet.sdk.ext.abbreviatedAddress
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import cash.z.wallet.sdk.ext.twig
import kotlinx.coroutines.delay
@ -37,11 +36,12 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
onExit()
}
binding.textConfirmation.text =
"Sending ${sendViewModel.zatoshiAmount.convertZatoshiToZecString(8)} ZEC to ${sendViewModel.toAddress.abbreviatedAddress()}"
"Sending ${sendViewModel.zatoshiAmount.convertZatoshiToZecString(8)} ZEC to ${sendViewModel.toAddress.toAbbreviatedAddress()}"
sendViewModel.memo?.trim()?.isNotEmpty()?.let { hasMemo ->
binding.radioIncludeAddress.isChecked = hasMemo
binding.radioIncludeAddress.goneIf(!hasMemo)
}
mainActivity?.preventBackPress(this)
}
override fun onAttach(context: Context) {
@ -91,6 +91,6 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
}
private fun onExit() {
mainActivity?.navController?.popBackStack(R.id.send_navigation, true)
mainActivity?.navController?.popBackStack(R.id.nav_send_address, true)
}
}

View File

@ -7,8 +7,7 @@ import android.view.inputmethod.EditorInfo
import cash.z.ecc.android.R
import cash.z.ecc.android.databinding.FragmentSendMemoBinding
import cash.z.ecc.android.di.viewmodel.activityViewModel
import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.ext.onClickNavBack
import cash.z.ecc.android.ext.onClickNavTo
import cash.z.ecc.android.ui.base.BaseFragment
class SendMemoFragment : BaseFragment<FragmentSendMemoBinding>() {
@ -28,7 +27,10 @@ class SendMemoFragment : BaseFragment<FragmentSendMemoBinding>() {
sendViewModel.memo = ""
mainActivity?.navController?.navigate(R.id.action_nav_send_memo_to_send_confirm)
}
binding.backButtonHitArea.onClickNavBack()
R.id.action_nav_send_memo_to_nav_send_address.let {
binding.backButtonHitArea.onClickNavTo(it)
onBackPressNavTo(it)
}
binding.radioIncludeAddress.setOnClickListener {
if (binding.radioIncludeAddress.isActivated) {
binding.radioIncludeAddress.isChecked = false

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="100%" android:toYDelta="0%"
android:duration="300" />
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300" />
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300" />
</set>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:interpolator="@android:interpolator/decelerate_cubic"
android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:interpolator="@android:interpolator/decelerate_cubic"
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>

View File

@ -91,17 +91,19 @@
<TextView
android:id="@+id/text_address_error"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="@font/inconsolata"
android:includeFontPadding="false"
android:textColor="@android:color/holo_red_light"
android:maxLines="1"
android:autoSizeTextType="uniform"
android:textSize="14dp"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/button_next"
app:layout_constraintStart_toStartOf="@+id/input_zcash_amount"
app:layout_constraintTop_toTopOf="@+id/button_next"
tools:text="Please enter a larger amount of money" />
app:layout_constraintEnd_toStartOf="@id/button_next"
tools:text="Please enter a larger amount of money also please enter a shorter sentence" />
<!-- Scan QR code -->
<ImageView

View File

@ -15,16 +15,22 @@
app:destination="@id/nav_receive" />
<action
android:id="@+id/action_nav_home_to_nav_detail"
app:destination="@id/nav_detail" />
app:destination="@id/nav_detail"
app:enterAnim="@anim/anim_enter_from_bottom" />
<action
android:id="@+id/action_nav_home_to_create_wallet"
app:destination="@id/nav_landing" />
<action
android:id="@+id/action_nav_home_to_send"
app:destination="@id/nav_send_address" />
app:destination="@id/nav_send_address"
app:exitAnim="@anim/anim_exit_to_left"
app:enterAnim="@anim/anim_enter_from_right"/>
<action
android:id="@+id/action_nav_home_to_nav_scan"
app:destination="@id/nav_scan" />
<action
android:id="@+id/action_nav_home_to_nav_profile"
app:destination="@id/nav_profile" />
</fragment>
<fragment
@ -57,13 +63,17 @@
<fragment
android:id="@+id/nav_detail"
android:name="cash.z.ecc.android.ui.detail.WalletDetailFragment"
tools:layout="@layout/fragment_detail" >
tools:layout="@layout/fragment_detail" />
<fragment
android:id="@+id/nav_profile"
android:name="cash.z.ecc.android.ui.profile.ProfileFragment"
tools:layout="@layout/fragment_profile" >
<action
android:id="@+id/action_nav_detail_to_backup_wallet"
android:id="@+id/action_nav_profile_to_nav_backup"
app:destination="@id/nav_backup" />
</fragment>
<!-- -->
<!-- Send Navigation -->
<!-- -->
@ -74,10 +84,17 @@
tools:layout="@layout/fragment_send_address" >
<action
android:id="@+id/action_nav_send_address_to_send_memo"
app:destination="@id/nav_send_memo"/>
app:destination="@id/nav_send_memo"
app:exitAnim="@anim/anim_exit_to_left"
app:enterAnim="@anim/anim_enter_from_right"/>
<action
android:id="@+id/action_nav_send_address_to_nav_scan"
app:destination="@id/nav_scan" />
<action
android:id="@+id/action_nav_send_address_to_nav_home"
app:destination="@id/nav_home"
app:enterAnim="@anim/anim_enter_from_left"
app:exitAnim="@anim/anim_exit_to_right"/>
</fragment>
<fragment
@ -86,7 +103,14 @@
tools:layout="@layout/fragment_send_memo" >
<action
android:id="@+id/action_nav_send_memo_to_send_confirm"
app:destination="@id/nav_send_confirm"/>
app:destination="@id/nav_send_confirm"
app:exitAnim="@anim/anim_exit_to_left"
app:enterAnim="@anim/anim_enter_from_right"/>
<action
android:id="@+id/action_nav_send_memo_to_nav_send_address"
app:destination="@id/nav_send_address"
app:enterAnim="@anim/anim_enter_from_left"
app:exitAnim="@anim/anim_exit_to_right" />
</fragment>
<fragment
@ -95,7 +119,15 @@
tools:layout="@layout/fragment_send_confirm" >
<action
android:id="@+id/action_nav_send_confirm_to_send_final"
app:destination="@id/nav_send_final"/>
app:destination="@id/nav_send_final"
app:popUpTo="@id/nav_send_confirm"
app:popUpToInclusive="true"
app:enterAnim="@anim/anim_fade_in"/>
<action
android:id="@+id/action_nav_send_confirm_to_nav_send_memo"
app:destination="@id/nav_send_memo"
app:enterAnim="@anim/anim_enter_from_left"
app:exitAnim="@anim/anim_exit_to_right" />
</fragment>
<fragment