diff --git a/app/src/main/java/com/tunjid/androidx/MainActivity.kt b/app/src/main/java/com/tunjid/androidx/MainActivity.kt index aa336bf6..745b98ac 100644 --- a/app/src/main/java/com/tunjid/androidx/MainActivity.kt +++ b/app/src/main/java/com/tunjid/androidx/MainActivity.kt @@ -35,6 +35,7 @@ class MainActivity : AppCompatActivity(), GlobalUiHost, Navigator.Controller { stackCount = tabs.size, containerId = R.id.content_container, backStackType = MultiStackNavigator.BackStackType.Unlimited, + stopInvalidNavigation = true, rootFunction = RouteFragment.Companion::newInstance, ) diff --git a/app/src/main/java/com/tunjid/androidx/tabnav/navigator/IndependentStacksFragment.kt b/app/src/main/java/com/tunjid/androidx/tabnav/navigator/IndependentStacksFragment.kt index 65e41d41..92b9f53a 100644 --- a/app/src/main/java/com/tunjid/androidx/tabnav/navigator/IndependentStacksFragment.kt +++ b/app/src/main/java/com/tunjid/androidx/tabnav/navigator/IndependentStacksFragment.kt @@ -102,6 +102,7 @@ class IndependentStacksFragment : Fragment(R.layout.fragment_independent_stack) private fun navigatorFor(id: Int) = navigators.getOrPut(id) { val stackNavigator by childStackNavigationController( containerId = id, + stopInvalidNavigation = true ) stackNavigator.apply { transactionModifier = { crossFade() } } } diff --git a/app/src/main/java/com/tunjid/androidx/tabnav/navigator/MultipleStacksFragment.kt b/app/src/main/java/com/tunjid/androidx/tabnav/navigator/MultipleStacksFragment.kt index e5f74c8a..76ce9e41 100644 --- a/app/src/main/java/com/tunjid/androidx/tabnav/navigator/MultipleStacksFragment.kt +++ b/app/src/main/java/com/tunjid/androidx/tabnav/navigator/MultipleStacksFragment.kt @@ -56,6 +56,7 @@ class MultipleStacksFragment : Fragment(R.layout.fragment_multiple_stack) { internal val innerNavigator: MultiStackNavigator by childMultiStackNavigationController( stackCount = DESTINATIONS.size, containerId = R.id.inner_container, + stopInvalidNavigation = true, rootFunction = { index -> MultipleStackChildFragment.newInstance(getChildName(index), 1) } diff --git a/navigation/src/androidTest/java/com/tunjid/androidx/navigation/MultiStackNavigatorTest.kt b/navigation/src/androidTest/java/com/tunjid/androidx/navigation/MultiStackNavigatorTest.kt index 71092ac5..11528d9f 100644 --- a/navigation/src/androidTest/java/com/tunjid/androidx/navigation/MultiStackNavigatorTest.kt +++ b/navigation/src/androidTest/java/com/tunjid/androidx/navigation/MultiStackNavigatorTest.kt @@ -337,7 +337,8 @@ class MultiStackNavigatorTest { stateContainer = savedStateFor(activity, "test"), fragmentManager = activity.supportFragmentManager, backStackType = type, - containerId = activity.containerId + containerId = activity.containerId, + stopInvalidNavigation = true, ) { NavigationTestFragment.newInstance(TAGS[it]) } } diff --git a/navigation/src/androidTest/java/com/tunjid/androidx/navigation/StackNavigatorTest.kt b/navigation/src/androidTest/java/com/tunjid/androidx/navigation/StackNavigatorTest.kt index f54031f7..e0c9714b 100644 --- a/navigation/src/androidTest/java/com/tunjid/androidx/navigation/StackNavigatorTest.kt +++ b/navigation/src/androidTest/java/com/tunjid/androidx/navigation/StackNavigatorTest.kt @@ -48,7 +48,11 @@ class StackNavigatorTest { @Before fun setUp() { activity = activityRule.activity as NavigationTestActivity - stackNavigator = StackNavigator(activity.supportFragmentManager, activity.containerId) + stackNavigator = StackNavigator( + fragmentManager = activity.supportFragmentManager, + containerId = activity.containerId, + stopInvalidNavigation = true + ) } @After @@ -74,7 +78,11 @@ class StackNavigatorTest { // create new instance of StackNavigator and confirm all // the old tags are restored - val copy = StackNavigator(activity.supportFragmentManager, activity.containerId) + val copy = StackNavigator( + fragmentManager = activity.supportFragmentManager, + containerId = activity.containerId, + stopInvalidNavigation = true + ) assertTrue(copy.fragmentTags.contains(testFragment.stableTag)) assertTrue(copy.fragmentTags.size == 1) diff --git a/navigation/src/main/java/com/tunjid/androidx/navigation/MultiStackNavigator.kt b/navigation/src/main/java/com/tunjid/androidx/navigation/MultiStackNavigator.kt index b1c6ba7b..b2a3bf0a 100644 --- a/navigation/src/main/java/com/tunjid/androidx/navigation/MultiStackNavigator.kt +++ b/navigation/src/main/java/com/tunjid/androidx/navigation/MultiStackNavigator.kt @@ -1,6 +1,7 @@ package com.tunjid.androidx.navigation import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -26,7 +27,8 @@ fun Fragment.childMultiStackNavigationController( stackCount: Int, @IdRes containerId: Int, backStackType: MultiStackNavigator.BackStackType = MultiStackNavigator.BackStackType.UniqueEntries, - rootFunction: (Int) -> Fragment + stopInvalidNavigation: Boolean, + rootFunction: (Int) -> Fragment, ): Lazy = lazy { MultiStackNavigator( stackCount = stackCount, @@ -34,7 +36,8 @@ fun Fragment.childMultiStackNavigationController( fragmentManager = childFragmentManager, containerId = containerId, backStackType = backStackType, - rootFunction = rootFunction + rootFunction = rootFunction, + stopInvalidNavigation = stopInvalidNavigation ) } @@ -42,7 +45,8 @@ fun FragmentActivity.multiStackNavigationController( stackCount: Int, @IdRes containerId: Int, backStackType: MultiStackNavigator.BackStackType = MultiStackNavigator.BackStackType.UniqueEntries, - rootFunction: (Int) -> Fragment + stopInvalidNavigation: Boolean, + rootFunction: (Int) -> Fragment, ): Lazy = lazy { MultiStackNavigator( stackCount = stackCount, @@ -50,7 +54,8 @@ fun FragmentActivity.multiStackNavigationController( fragmentManager = supportFragmentManager, containerId = containerId, backStackType = backStackType, - rootFunction = rootFunction + rootFunction = rootFunction, + stopInvalidNavigation = stopInvalidNavigation ) } @@ -64,7 +69,9 @@ class MultiStackNavigator( private val fragmentManager: FragmentManager, @IdRes override val containerId: Int, backStackType: BackStackType = BackStackType.UniqueEntries, - private val rootFunction: (Int) -> Fragment) : Navigator { + private val stopInvalidNavigation: Boolean, + private val rootFunction: (Int) -> Fragment, +) : Navigator { /** * A callback that will be invoked when a stack is selected, either by the user selecting it, @@ -213,7 +220,14 @@ class MultiStackNavigator( private fun FragmentTransaction.addStackFragments() { indices.forEach { index -> stackTransactionModifier?.invoke(this, index) - add(containerId, StackFragment.newInstance(index), index.toString()) + add( + containerId, + StackFragment.newInstance( + index = index, + stopInvalidNavigation = stopInvalidNavigation + ), + index.toString() + ) } } @@ -225,6 +239,11 @@ class MultiStackNavigator( if (id != this@MultiStackNavigator.containerId) return check(this is StackFragment) { "Only Stack Fragments may be added to a container View managed by a MultiStackNavigator" } + if (stopInvalidNavigation && fm.isStateSaved) { + Log.i("StackNavigator", "Ignoring push call in onFragmentCreated, FragmentManager is in an invalid state") + return + } + if (index != stackVisitor.currentHost() && isAttached) fm.commit { detach(this@run) } } @@ -252,15 +271,30 @@ class StackFragment : Fragment() { internal var index: Int by fragmentArgs() private var containerId: Int by fragmentArgs() + private var stopInvalidNavigation: Boolean by fragmentArgs() internal val hasNoRoot get() = navigator.current == null - internal val navigator by lazy { StackNavigator(childFragmentManager, containerId) } + internal val navigator by lazy { + StackNavigator( + fragmentManager = childFragmentManager, + containerId = containerId, + stopInvalidNavigation = stopInvalidNavigation, + ) + } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = FragmentContainerView(inflater.context).apply { id = containerId } companion object { - internal fun newInstance(index: Int) = StackFragment().apply { this.index = index; containerId = View.generateViewId() } + internal fun newInstance( + index: Int, + stopInvalidNavigation: Boolean + ) = + StackFragment().apply { + this.index = index + this.stopInvalidNavigation = stopInvalidNavigation + containerId = View.generateViewId() + } } } diff --git a/navigation/src/main/java/com/tunjid/androidx/navigation/StackNavigator.kt b/navigation/src/main/java/com/tunjid/androidx/navigation/StackNavigator.kt index b2df853f..e1a2008a 100644 --- a/navigation/src/main/java/com/tunjid/androidx/navigation/StackNavigator.kt +++ b/navigation/src/main/java/com/tunjid/androidx/navigation/StackNavigator.kt @@ -12,13 +12,27 @@ import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -fun Fragment.childStackNavigationController(@IdRes containerId: Int): Lazy = lazy { - StackNavigator(childFragmentManager, containerId) +fun Fragment.childStackNavigationController( + @IdRes containerId: Int, + stopInvalidNavigation: Boolean +): Lazy = lazy { + StackNavigator( + fragmentManager = childFragmentManager, + containerId = containerId, + stopInvalidNavigation = stopInvalidNavigation + ) } @Suppress("unused") -fun FragmentActivity.stackNavigationController(@IdRes containerId: Int): Lazy = lazy { - StackNavigator(supportFragmentManager, containerId) +fun FragmentActivity.stackNavigationController( + @IdRes containerId: Int, + stopInvalidNavigation: Boolean +): Lazy = lazy { + StackNavigator( + fragmentManager = supportFragmentManager, + containerId = containerId, + stopInvalidNavigation = stopInvalidNavigation + ) } /** @@ -33,7 +47,8 @@ fun FragmentActivity.stackNavigationController(@IdRes containerId: Int): Lazy