Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/java/com/tunjid/androidx/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() } }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -26,31 +27,35 @@ fun Fragment.childMultiStackNavigationController(
stackCount: Int,
@IdRes containerId: Int,
backStackType: MultiStackNavigator.BackStackType = MultiStackNavigator.BackStackType.UniqueEntries,
rootFunction: (Int) -> Fragment
stopInvalidNavigation: Boolean,
rootFunction: (Int) -> Fragment,
): Lazy<MultiStackNavigator> = lazy {
MultiStackNavigator(
stackCount = stackCount,
stateContainer = savedStateFor(this@childMultiStackNavigationController, "$MULTI_STACK_NAVIGATOR-$containerId"),
fragmentManager = childFragmentManager,
containerId = containerId,
backStackType = backStackType,
rootFunction = rootFunction
rootFunction = rootFunction,
stopInvalidNavigation = stopInvalidNavigation
)
}

fun FragmentActivity.multiStackNavigationController(
stackCount: Int,
@IdRes containerId: Int,
backStackType: MultiStackNavigator.BackStackType = MultiStackNavigator.BackStackType.UniqueEntries,
rootFunction: (Int) -> Fragment
stopInvalidNavigation: Boolean,
rootFunction: (Int) -> Fragment,
): Lazy<MultiStackNavigator> = lazy {
MultiStackNavigator(
stackCount = stackCount,
stateContainer = savedStateFor(this@multiStackNavigationController, "$MULTI_STACK_NAVIGATOR-$containerId"),
fragmentManager = supportFragmentManager,
containerId = containerId,
backStackType = backStackType,
rootFunction = rootFunction
rootFunction = rootFunction,
stopInvalidNavigation = stopInvalidNavigation
)
}

Expand All @@ -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,
Expand Down Expand Up @@ -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()
)
}
}

Expand All @@ -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) }
}

Expand Down Expand Up @@ -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()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,27 @@ import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

fun Fragment.childStackNavigationController(@IdRes containerId: Int): Lazy<StackNavigator> = lazy {
StackNavigator(childFragmentManager, containerId)
fun Fragment.childStackNavigationController(
@IdRes containerId: Int,
stopInvalidNavigation: Boolean
): Lazy<StackNavigator> = lazy {
StackNavigator(
fragmentManager = childFragmentManager,
containerId = containerId,
stopInvalidNavigation = stopInvalidNavigation
)
}

@Suppress("unused")
fun FragmentActivity.stackNavigationController(@IdRes containerId: Int): Lazy<StackNavigator> = lazy {
StackNavigator(supportFragmentManager, containerId)
fun FragmentActivity.stackNavigationController(
@IdRes containerId: Int,
stopInvalidNavigation: Boolean
): Lazy<StackNavigator> = lazy {
StackNavigator(
fragmentManager = supportFragmentManager,
containerId = containerId,
stopInvalidNavigation = stopInvalidNavigation
)
}

/**
Expand All @@ -33,7 +47,8 @@ fun FragmentActivity.stackNavigationController(@IdRes containerId: Int): Lazy<St

class StackNavigator constructor(
internal val fragmentManager: FragmentManager,
@param:IdRes @field:IdRes @get:IdRes override val containerId: Int
@param:IdRes @field:IdRes @get:IdRes override val containerId: Int,
private val stopInvalidNavigation: Boolean,
) : Navigator {

/**
Expand Down Expand Up @@ -93,6 +108,11 @@ class StackNavigator constructor(
(if (fragmentAlreadyExists) fragmentManager.findFragmentByTag(tag)
else fragment) ?: throw NullPointerException(MSG_DODGY_FRAGMENT)

if (stopInvalidNavigation && fragmentManager.isStateSaved) {
Log.i("StackNavigator", "Ignoring push call, FragmentManager is in an invalid state")
return fragmentShown
}

fragmentManager.commit {
transactionModifier?.invoke(this, fragment)
replace(containerId, fragmentToShow, tag)
Expand Down