Merge "Add popUpCurrent to navController"

This commit is contained in:
Chaohui Wang
2023-01-19 09:01:35 +00:00
committed by Android (Google) Code Review
3 changed files with 120 additions and 7 deletions

View File

@@ -25,7 +25,7 @@ import androidx.compose.runtime.remember
import androidx.navigation.NavHostController
interface NavControllerWrapper {
fun navigate(route: String)
fun navigate(route: String, popUpCurrent: Boolean = false)
fun navigateBack()
val highlightEntryId: String?
@@ -48,17 +48,17 @@ fun NavHostController.localNavController(): ProvidedValue<NavControllerWrapper>
val LocalNavController = compositionLocalOf<NavControllerWrapper> {
object : NavControllerWrapper {
override fun navigate(route: String) {}
override fun navigate(route: String, popUpCurrent: Boolean) {}
override fun navigateBack() {}
}
}
@Composable
fun navigator(route: String?): () -> Unit {
fun navigator(route: String?, popUpCurrent: Boolean = false): () -> Unit {
if (route == null) return {}
val navController = LocalNavController.current
return { navController.navigate(route) }
return { navController.navigate(route, popUpCurrent) }
}
internal class NavControllerWrapperImpl(
@@ -68,8 +68,16 @@ internal class NavControllerWrapperImpl(
var highlightId: String? = null
var sessionName: String? = null
override fun navigate(route: String) {
navController.navigate(route)
override fun navigate(route: String, popUpCurrent: Boolean) {
navController.navigate(route) {
if (popUpCurrent) {
navController.currentDestination?.let { currentDestination ->
popUpTo(currentDestination.id) {
inclusive = true
}
}
}
}
}
override fun navigateBack() {

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settingslib.spa.framework.compose
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.waitUntilExists
import kotlinx.coroutines.delay
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class NavControllerWrapperTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun navigate_canNavigate() {
composeTestRule.setContent {
TestNavHost {
LocalNavController.current.navigate(ROUTE_B)
}
}
composeTestRule.onNodeWithText(ROUTE_B).assertIsDisplayed()
}
@Test
fun navigate_canNavigateBack() {
composeTestRule.setContent {
TestNavHost {
val navController = LocalNavController.current
LaunchedEffect(Unit) {
navController.navigate(ROUTE_B)
delay(100)
navController.navigateBack()
}
}
}
composeTestRule.waitUntilExists(hasText(ROUTE_A))
}
@Test
fun navigate_canNavigateAndPopUpCurrent() {
composeTestRule.setContent {
TestNavHost {
val navController = LocalNavController.current
LaunchedEffect(Unit) {
navController.navigate(ROUTE_B)
delay(100)
navController.navigate(ROUTE_C, popUpCurrent = true)
delay(100)
navController.navigateBack()
}
}
}
composeTestRule.waitUntilExists(hasText(ROUTE_A))
}
private companion object {
@Composable
fun TestNavHost(content: @Composable () -> Unit) {
val navController = rememberNavController()
CompositionLocalProvider(navController.localNavController()) {
NavHost(navController, ROUTE_A) {
composable(route = ROUTE_A) { Text(ROUTE_A) }
composable(route = ROUTE_B) { Text(ROUTE_B) }
composable(route = ROUTE_C) { Text(ROUTE_C) }
}
content()
}
}
const val ROUTE_A = "RouteA"
const val ROUTE_B = "RouteB"
const val ROUTE_C = "RouteC"
}
}

View File

@@ -25,7 +25,7 @@ class FakeNavControllerWrapper : NavControllerWrapper {
var navigateCalledWith: String? = null
var navigateBackIsCalled = false
override fun navigate(route: String) {
override fun navigate(route: String, popUpCurrent: Boolean) {
navigateCalledWith = route
}