All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cmpMain.com.eygraber.compose.material3.navigation.ModalBottomSheetNavigator.cmp.kt Maven / Gradle / Ivy

There is a newer version: 0.0.6
Show newest version
package com.eygraber.compose.material3.navigation

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.ModalBottomSheetProperties
import androidx.compose.runtime.Composable
import androidx.navigation.FloatingWindow
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination
import androidx.navigation.NavOptions
import androidx.navigation.Navigator
import com.eygraber.compose.material3.navigation.ModalBottomSheetNavigator.Destination
import kotlinx.coroutines.flow.MutableStateFlow

/**
 * Navigator that navigates through [Composable]s that will be hosted within a [ModalBottomSheet]. Every
 * destination using this Navigator must set a valid [Composable] by setting it directly on an
 * instantiated [Destination] or calling [bottomSheet].
 */
public actual class ModalBottomSheetNavigator actual constructor() : Navigator(NAME) {
  /** Get the back stack from the [state]. */
  internal actual val backStack
    get() = when {
      isAttached -> state.backStack
      else -> MutableStateFlow(emptyList())
    }

  /** Get the transitioning modal bottom sheets from the [state]. */
  internal actual val transitionInProgress
    get() = when {
      isAttached -> state.transitionsInProgress
      else -> MutableStateFlow(emptySet())
    }

  /** Dismiss the modal bottom sheets destination associated with the given [backStackEntry]. */
  internal actual fun dismiss(backStackEntry: NavBackStackEntry) {
    popBackStack(backStackEntry, false)
  }

  internal actual fun onTransitionComplete(entry: NavBackStackEntry) {
    state.markTransitionComplete(entry)
  }

  actual override fun navigate(
    entries: List,
    navOptions: NavOptions?,
    navigatorExtras: Extras?,
  ) {
    entries.forEach { entry -> state.push(entry) }
  }

  @ExperimentalMaterial3Api
  actual override fun createDestination(): Destination = Destination(this) {}

  actual override fun popBackStack(popUpTo: NavBackStackEntry, savedState: Boolean) {
    state.popWithTransition(popUpTo, savedState)
    // When popping, the incoming modal bottom sheet is marked transitioning to hold it in
    // STARTED. With pop complete, we can remove it from transition so it can move to RESUMED.
    val popIndex = state.transitionsInProgress.value.indexOf(popUpTo)
    // do not mark complete for entries up to and including popUpTo
    state.transitionsInProgress.value.forEachIndexed { index, entry ->
      if(index > popIndex) onTransitionComplete(entry)
    }
  }

  /** NavDestination specific to [ModalBottomSheetNavigator] */
  public actual class Destination @ExperimentalMaterial3Api
  actual constructor(
    navigator: ModalBottomSheetNavigator,
    internal actual val properties: ModalBottomSheetProperties,
    internal actual val skipPartiallyExpanded: Boolean,
    internal actual val content: @Composable (NavBackStackEntry) -> Unit,
  ) : NavDestination(navigator), FloatingWindow

  internal actual companion object {
    internal actual const val NAME = "modalBottomSheet"
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy