Merge remote-tracking branch 'origin/main' into claude/audio-rooms-android-ui-PIpFN
This commit is contained in:
+12
-9
@@ -34,19 +34,22 @@ import androidx.navigation.NavGraphBuilder
|
|||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.toRoute
|
import androidx.navigation.toRoute
|
||||||
|
|
||||||
// Per-entry hint stored on NavBackStackEntry.savedStateHandle by
|
// Per-entry hint stamped by Nav.navBottomBar marking that the entry was
|
||||||
// Nav.navBottomBar. When present, composableFromEnd skips the horizontal
|
// reached via a bottom-nav tab. Used in two places:
|
||||||
// slide so bottom-bar taps fall back to the NavHost-level fade.
|
// - composableFromEnd skips the horizontal slide on tab entries so
|
||||||
const val SKIP_SLIDE_ANIMATION_KEY = "skipSlideAnimation"
|
// bottom-bar taps fall back to the NavHost-level fade.
|
||||||
|
// - Nav.canPop hides the back arrow on tab roots even though Home
|
||||||
|
// sits below them in the stack.
|
||||||
|
const val BOTTOM_NAV_ROOT_KEY = "bottomNavRoot"
|
||||||
|
|
||||||
fun NavBackStackEntry.skipsSlideAnimation(): Boolean = savedStateHandle.get<Boolean>(SKIP_SLIDE_ANIMATION_KEY) == true
|
fun NavBackStackEntry.isBottomNavRoot(): Boolean = savedStateHandle.get<Boolean>(BOTTOM_NAV_ROOT_KEY) == true
|
||||||
|
|
||||||
inline fun <reified T : Any> NavGraphBuilder.composableFromEnd(noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit) {
|
inline fun <reified T : Any> NavGraphBuilder.composableFromEnd(noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit) {
|
||||||
composable<T>(
|
composable<T>(
|
||||||
enterTransition = { if (targetState.skipsSlideAnimation()) null else slideInHorizontallyFromEnd },
|
enterTransition = { if (targetState.isBottomNavRoot()) null else slideInHorizontallyFromEnd },
|
||||||
exitTransition = { if (targetState.skipsSlideAnimation()) null else scaleOut },
|
exitTransition = { if (targetState.isBottomNavRoot()) null else scaleOut },
|
||||||
popEnterTransition = { if (initialState.skipsSlideAnimation()) null else scaleIn },
|
popEnterTransition = { if (initialState.isBottomNavRoot()) null else scaleIn },
|
||||||
popExitTransition = { if (initialState.skipsSlideAnimation()) null else slideOutHorizontallyToEnd },
|
popExitTransition = { if (initialState.isBottomNavRoot()) null else slideOutHorizontallyToEnd },
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import android.annotation.SuppressLint
|
|||||||
import androidx.compose.material3.DrawerState
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.SKIP_SLIDE_ANIMATION_KEY
|
import com.vitorpamplona.amethyst.ui.navigation.BOTTOM_NAV_ROOT_KEY
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.isBottomNavRoot
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.getRouteWithArguments
|
import com.vitorpamplona.amethyst.ui.navigation.routes.getRouteWithArguments
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -79,22 +79,25 @@ class Nav(
|
|||||||
override fun navBottomBar(route: Route) {
|
override fun navBottomBar(route: Route) {
|
||||||
navigationScope.launch {
|
navigationScope.launch {
|
||||||
controller.navigate(route) {
|
controller.navigate(route) {
|
||||||
// Clear the back stack down to and including the graph's start
|
// Clear sibling bottom-nav entries but keep Home (the start
|
||||||
// destination so a bottom-nav tap leaves only the new route in
|
// destination) below, so back-swipe from any tab returns to
|
||||||
// the stack. Without inclusive=true, Home would remain below
|
// Home and back-swipe from Home leaves the app.
|
||||||
// the new tab and canPop() would wrongly show a back arrow.
|
popUpTo(Route.Home) {
|
||||||
popUpTo(controller.graph.findStartDestination().id) {
|
inclusive = false
|
||||||
inclusive = true
|
|
||||||
}
|
}
|
||||||
launchSingleTop = true
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
// Stamp the entry so composableFromEnd's transition lambdas can
|
// Mark this entry as a tab root: hides the back arrow in canPop
|
||||||
// skip the slide animation when this entry enters or exits.
|
// and skips the horizontal slide in composableFromEnd.
|
||||||
controller.getBackStackEntry(route).savedStateHandle[SKIP_SLIDE_ANIMATION_KEY] = true
|
controller.getBackStackEntry(route).savedStateHandle[BOTTOM_NAV_ROOT_KEY] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canPop(): Boolean = controller.previousBackStackEntry != null
|
override fun canPop(): Boolean {
|
||||||
|
val current = controller.currentBackStackEntry ?: return false
|
||||||
|
if (current.isBottomNavRoot()) return false
|
||||||
|
return controller.previousBackStackEntry != null
|
||||||
|
}
|
||||||
|
|
||||||
override fun popBack() {
|
override fun popBack() {
|
||||||
navigationScope.launch {
|
navigationScope.launch {
|
||||||
|
|||||||
Reference in New Issue
Block a user