diff --git a/.run/_app_androidTest.run.xml b/.run/_app_androidTest.run.xml
new file mode 100644
index 0000000..d001c28
--- /dev/null
+++ b/.run/_app_androidTest.run.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/androidTest/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragmentTest.kt b/app/src/androidTest/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragmentTest.kt
index c7bc11f..4922420 100644
--- a/app/src/androidTest/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragmentTest.kt
+++ b/app/src/androidTest/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragmentTest.kt
@@ -26,8 +26,8 @@ import org.junit.runner.RunWith
class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
@Test
@MediumTest
- fun dismiss_returns_home() {
- val fragmentNavigationScenario = newScenario()
+ fun dismiss_returns_home_when_autoshield_not_available() {
+ val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
onView(withId(cash.z.ecc.android.R.id.button_autoshield_dismiss)).also {
it.perform(ViewActions.click())
@@ -41,23 +41,23 @@ class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
@Test
@MediumTest
- fun dismiss_sets_preference() {
- newScenario()
+ fun dismiss_starts_autoshield_when_autoshield_available() {
+ val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = true)
onView(withId(cash.z.ecc.android.R.id.button_autoshield_dismiss)).also {
it.perform(ViewActions.click())
}
assertThat(
- Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(ApplicationProvider.getApplicationContext()),
- equalTo(true)
+ fragmentNavigationScenario.navigationController.currentDestination?.id,
+ equalTo(cash.z.ecc.android.R.id.nav_shield_final)
)
}
@Test
@MediumTest
fun clicking_more_info_launches_browser() {
- val fragmentNavigationScenario = newScenario()
+ val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
onView(withId(cash.z.ecc.android.R.id.button_autoshield_more_info)).also {
it.perform(ViewActions.click())
@@ -72,27 +72,12 @@ class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
// navigation component works.
}
- @Test
- @MediumTest
- fun clicking_more_info_sets_preference() {
- newScenario()
-
- onView(withId(cash.z.ecc.android.R.id.button_autoshield_more_info)).also {
- it.perform(ViewActions.click())
- }
-
- assertThat(
- Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(ApplicationProvider.getApplicationContext()),
- equalTo(true)
- )
- }
-
@Test
@MediumTest
fun starting_fragment_does_not_launch_activities() {
Intents.init()
try {
- val fragmentNavigationScenario = newScenario()
+ val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
// The test framework launches an Activity to host the Fragment under test
// Since the class name is not a public API, this could break in the future with newer
@@ -121,8 +106,19 @@ class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
@Test
@MediumTest
- fun back_does_not_set_preference() {
- val fragmentNavigationScenario = newScenario()
+ fun display_fragment_sets_preference() {
+ newScenario(isAutoshieldAvailable = false)
+
+ assertThat(
+ Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(ApplicationProvider.getApplicationContext()),
+ equalTo(true)
+ )
+ }
+
+ @Test
+ @MediumTest
+ fun back_navigates_home() {
+ val fragmentNavigationScenario = newScenario(isAutoshieldAvailable = false)
fragmentNavigationScenario.fragmentScenario.onFragment {
// Probably closest we can come to simulating back with the navigation test framework
@@ -133,15 +129,10 @@ class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
fragmentNavigationScenario.navigationController.currentDestination?.id,
equalTo(cash.z.ecc.android.R.id.nav_home)
)
-
- assertThat(
- Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(ApplicationProvider.getApplicationContext()),
- equalTo(false)
- )
}
companion object {
- private fun newScenario(): FragmentNavigationScenario {
+ private fun newScenario(isAutoshieldAvailable: Boolean): FragmentNavigationScenario {
// Clear preferences for each scenario, as this most closely reflects how this fragment
// is used in the app, as it is displayed usually on first launch
SharedPreferenceFactory.getSharedPreferences(ApplicationProvider.getApplicationContext())
@@ -149,7 +140,7 @@ class AutoshieldingInformationFragmentTest : UiTestPrerequisites() {
val scenario = FragmentScenario.launchInContainer(
AutoshieldingInformationFragment::class.java,
- null,
+ HomeFragmentDirections.actionNavHomeToAutoshieldingInfo(isAutoshieldAvailable).arguments,
cash.z.ecc.android.R.style.ZcashTheme,
null
)
diff --git a/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt b/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt
index ded0dc3..da7689a 100644
--- a/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt
+++ b/app/src/main/java/cash/z/ecc/android/ui/MainActivity.kt
@@ -49,6 +49,7 @@ import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
+import androidx.navigation.NavDirections
import androidx.navigation.Navigator
import androidx.navigation.findNavController
import cash.z.ecc.android.R
@@ -220,11 +221,13 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
navController?.popBackStack(destination, inclusive)
}
- fun safeNavigate(@IdRes destination: Int, extras: Navigator.Extras? = null) {
+ fun safeNavigate(navDirections: NavDirections) = safeNavigate(navDirections.actionId, navDirections.arguments, null)
+
+ fun safeNavigate(@IdRes destination: Int, args: Bundle? = null, extras: Navigator.Extras? = null) {
if (navController == null) {
navInitListeners.add {
try {
- navController?.navigate(destination, null, null, extras)
+ navController?.navigate(destination, args, null, extras)
} catch (t: Throwable) {
twig(
"WARNING: during callback, did not navigate to destination: R.id.${
@@ -237,7 +240,7 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
}
} else {
try {
- navController?.navigate(destination, null, null, extras)
+ navController?.navigate(destination, args, null, extras)
} catch (t: Throwable) {
twig(
"WARNING: did not immediately navigate to destination: R.id.${
diff --git a/app/src/main/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragment.kt
index 11d5579..d6a6609 100644
--- a/app/src/main/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragment.kt
+++ b/app/src/main/java/cash/z/ecc/android/ui/home/AutoshieldingInformationFragment.kt
@@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.navigation.fragment.findNavController
-import cash.z.ecc.android.R
+import androidx.navigation.fragment.navArgs
import cash.z.ecc.android.databinding.FragmentAutoShieldInformationBinding
import cash.z.ecc.android.ext.requireApplicationContext
import cash.z.ecc.android.feedback.Report
@@ -12,33 +12,46 @@ import cash.z.ecc.android.preference.Preferences
import cash.z.ecc.android.preference.model.put
import cash.z.ecc.android.ui.base.BaseFragment
-/*
- * If the user presses the Android back button, the backstack will be popped and the user returns
- * to the app home screen. The preference will not be set in that case, because it could be considered
- * that the user did not acknowledge this prompt.
- */
class AutoshieldingInformationFragment : BaseFragment() {
override val screen = Report.Screen.AUTO_SHIELD_INFORMATION
+ private val args: AutoshieldingInformationFragmentArgs by navArgs()
+
override fun inflate(inflater: LayoutInflater): FragmentAutoShieldInformationBinding =
FragmentAutoShieldInformationBinding.inflate(inflater)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
+ /*
+ * Once the fragment is displayed, acknowledge it was presented to the user. While it might
+ * be better to have explicit user interaction (positive/negative button or back),
+ * this implementation is simpler. Hooking into the positive/negative button is easy, but
+ * hooking into the back button from a Fragment ends up being gross.
+ *
+ * Always acknowledging is necessary, because the HomeFragment will otherwise almost immediately
+ * re-launch this Fragment when it refreshes the UI (and therefore re-runs the
+ * check as to whether the preference to display this fragment has been set).
+ */
+ acknowledge()
+
binding.buttonAutoshieldDismiss.setOnClickListener {
- Preferences.isAcknowledgedAutoshieldingInformationPrompt.put(
- requireApplicationContext(),
- true
- )
- findNavController().navigate(R.id.action_nav_autoshielding_info_to_home)
+ if (args.isStartAutoshield) {
+ // TODO: Move the call to track last autoshield time to the AutoShieldFragment
+ // Dislike this call here; it would likely be better to track last autoshield
+ // time from the fragment that actually does the autoshielding. Then the tracking
+ // is guaranteed to be called at the right time and we don't have this call scattered
+ // in several different places (e.g. here and in HomeFragment).
+ mainActivity?.lastAutoShieldTime = System.currentTimeMillis()
+
+ findNavController().navigate(AutoshieldingInformationFragmentDirections.actionNavAutoshieldingInfoToAutoshield())
+ } else {
+ findNavController().navigate(AutoshieldingInformationFragmentDirections.actionNavAutoshieldingInfoToHome())
+ }
}
binding.buttonAutoshieldMoreInfo.setOnClickListener {
- Preferences.isAcknowledgedAutoshieldingInformationPrompt.put(
- requireApplicationContext(),
- true
- )
try {
- findNavController().navigate(R.id.action_nav_autoshielding_info_to_browser)
+ findNavController().navigate(AutoshieldingInformationFragmentDirections.actionNavAutoshieldingInfoToBrowser())
} catch (e: Exception) {
// ActivityNotFoundException could happen on certain devices, like Android TV, Android Things, etc.
@@ -49,8 +62,15 @@ class AutoshieldingInformationFragment : BaseFragment() {
twig("Sync ready! Monitoring synchronizer state...")
monitorUiModelChanges()
- if (!Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(requireApplicationContext())) {
- mainActivity?.safeNavigate(R.id.action_nav_home_to_autoshielding_info)
- } else {
+ if (Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(requireApplicationContext())) {
maybeInterruptUser()
}
@@ -375,11 +373,23 @@ class HomeFragment : BaseFragment() {
}
private fun autoShield(uiModel: HomeViewModel.UiModel) {
+ // TODO: Move the preference read to a suspending function
+ // First time SharedPreferences are hit, it'll perform disk IO
+ val isAutoshieldingAcknowledged = Preferences.isAcknowledgedAutoshieldingInformationPrompt.get(requireApplicationContext())
+
if (uiModel.hasAutoshieldFunds && canAutoshield()) {
- twig("Autoshielding is available! Let's do this!!!")
- mainActivity?.lastAutoShieldTime = System.currentTimeMillis()
- mainActivity?.safeNavigate(R.id.action_nav_home_to_nav_funds_available)
+ if (!isAutoshieldingAcknowledged) {
+ mainActivity?.safeNavigate(HomeFragmentDirections.actionNavHomeToAutoshieldingInfo(true))
+ } else {
+ twig("Autoshielding is available! Let's do this!!!")
+ mainActivity?.lastAutoShieldTime = System.currentTimeMillis()
+ mainActivity?.safeNavigate(HomeFragmentDirections.actionNavHomeToNavFundsAvailable())
+ }
} else {
+ if (!isAutoshieldingAcknowledged) {
+ mainActivity?.safeNavigate(HomeFragmentDirections.actionNavHomeToAutoshieldingInfo(false))
+ }
+
// troubleshooting logs
if (uiModel.transparentBalance.availableZatoshi > 0) {
twig("Transparent funds are available but not enough to autoshield. Available: ${uiModel.transparentBalance.availableZatoshi.convertZatoshiToZecString(10)} Required: ${ZcashWalletApp.instance.autoshieldThreshold.convertZatoshiToZecString(8)}")
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index 83066f4..bc5764c 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -122,12 +122,19 @@
+ tools:layout="@layout/fragment_auto_shield_information"
+ >
+
+