Skip to content

Commit

Permalink
Commonize "material-navigation" module. (#1504)
Browse files Browse the repository at this point in the history
Make "material-navigation" multiplatform.

Fixes https://youtrack.jetbrains.com/issue/CMP-1365

## Testing
Checked the module manually
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/6f161ea1-1e97-474e-898b-0eadf253cb25">

```kotlin
commonMain.dependencies {
    implementation(compose.runtime)
    implementation(compose.foundation)
    implementation(compose.material)
    implementation("org.jetbrains.androidx.navigation:navigation-compose:...")
    implementation("org.jetbrains.compose.material:material-navigation:...")
}
```

```kotlin
@composable
internal fun App() = AppTheme {

    val bottomSheetNavigator = rememberBottomSheetNavigator()
    val navController = rememberNavController(bottomSheetNavigator)

    ModalBottomSheetLayout(bottomSheetNavigator) {
        NavHost(navController, startDestination = "start") {
            composable("start") {
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                    Column {
                        Text("START")
                        Button(onClick = { navController.navigate("screen_1") }) {
                            Text("NEXT")
                        }
                        Button(onClick = { navController.navigate("bottomSheet") }) {
                            Text("Bottom Sheet")
                        }
                    }
                }
            }
            composable("screen_1") {
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                    Column {
                        Text("SCREEN 1")
                        Button(onClick = { navController.popBackStack() }) {
                            Text("EXIT")
                        }
                    }
                }
            }
            bottomSheet("bottomSheet") {
                Box(contentAlignment = Alignment.Center) {
                    Column {
                        Text("Bottom Sheet")
                        Button(onClick = { navController.navigate("bottomSheet") }) {
                            Text("More sheet")
                        }
                        Button(onClick = { navController.popBackStack() }) {
                            Text("EXIT")
                        }
                    }
                }
            }
        }
    }
}
```

## Release Notes
### Features - Multiple Platforms
- New multiplatform module "material-navigation"
  • Loading branch information
terrakok authored Aug 27, 2024
1 parent 70d6caa commit c96b59a
Show file tree
Hide file tree
Showing 15 changed files with 530 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
public final class androidx/compose/material/navigation/BottomSheetKt {
public static final fun ModalBottomSheetLayout-4erKP6g (Landroidx/compose/material/navigation/BottomSheetNavigator;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;FJJJLkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
}

public final class androidx/compose/material/navigation/BottomSheetNavigator : androidx/navigation/Navigator {
public static final field $stable I
public fun <init> (Landroidx/compose/material/ModalBottomSheetState;)V
public fun createDestination ()Landroidx/compose/material/navigation/BottomSheetNavigator$Destination;
public synthetic fun createDestination ()Landroidx/navigation/NavDestination;
public final fun getNavigatorSheetState ()Landroidx/compose/material/navigation/BottomSheetNavigatorSheetState;
public fun navigate (Ljava/util/List;Landroidx/navigation/NavOptions;Landroidx/navigation/Navigator$Extras;)V
public fun onAttach (Landroidx/navigation/NavigatorState;)V
public fun popBackStack (Landroidx/navigation/NavBackStackEntry;Z)V
}

public final class androidx/compose/material/navigation/BottomSheetNavigator$Destination : androidx/navigation/NavDestination, androidx/navigation/FloatingWindow {
public static final field $stable I
public fun <init> (Landroidx/compose/material/navigation/BottomSheetNavigator;Lkotlin/jvm/functions/Function4;)V
}

public final class androidx/compose/material/navigation/BottomSheetNavigatorKt {
public static final fun rememberBottomSheetNavigator (Landroidx/compose/animation/core/AnimationSpec;Landroidx/compose/runtime/Composer;II)Landroidx/compose/material/navigation/BottomSheetNavigator;
}

public final class androidx/compose/material/navigation/BottomSheetNavigatorSheetState {
public static final field $stable I
public fun <init> (Landroidx/compose/material/ModalBottomSheetState;)V
public final fun getCurrentValue ()Landroidx/compose/material/ModalBottomSheetValue;
public final fun getTargetValue ()Landroidx/compose/material/ModalBottomSheetValue;
public final fun isVisible ()Z
}

public final class androidx/compose/material/navigation/ComposableSingletons$BottomSheetNavigator_jbKt {
public static final field INSTANCE Landroidx/compose/material/navigation/ComposableSingletons$BottomSheetNavigator_jbKt;
public static field lambda-1 Lkotlin/jvm/functions/Function4;
public fun <init> ()V
public final fun getLambda-1$material_navigation ()Lkotlin/jvm/functions/Function4;
}

public final class androidx/compose/material/navigation/NavGraphBuilderKt {
public static final fun bottomSheet (Landroidx/navigation/NavGraphBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function4;)V
public static synthetic fun bottomSheet$default (Landroidx/navigation/NavGraphBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)V
}

96 changes: 96 additions & 0 deletions compose/material/material-navigation/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2024 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.
*/

import androidx.build.AndroidXComposePlugin
import androidx.build.JetbrainsAndroidXPlugin
import androidx.build.LibraryType
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType

plugins {
id("AndroidXPlugin")
id("com.android.library")
id("AndroidXComposePlugin")
id("JetbrainsAndroidXPlugin")
}

AndroidXComposePlugin.applyAndConfigureKotlinPlugin(project)
JetbrainsAndroidXPlugin.applyAndConfigure(project)

androidXComposeMultiplatform {
android()
desktop()
darwin()
js()
wasm()
}

kotlin {
sourceSets {
commonMain {
dependencies {
implementation(project(":navigation:navigation-compose"))
implementation(project(":compose:material:material"))
implementation(libs.kotlinStdlib)
}
}

androidInstrumentedTest {
dependencies {
implementation(project(":compose:test-utils"))
implementation(project(":navigation:navigation-testing"))
implementation(project(":compose:ui:ui-test-junit4"))
implementation(project(":compose:ui:ui-test-manifest"))
implementation(libs.testRunner)
implementation(libs.junit)
implementation(libs.truth)
implementation(libs.testRules)
}
}

jbMain.dependsOn(commonMain)
desktopMain.dependsOn(jbMain)
nativeMain.dependsOn(jbMain)
webMain.dependsOn(jbMain)

targets.all { target ->
if (target.platformType == KotlinPlatformType.native) {
target.compilations["main"].defaultSourceSet {
dependsOn(nativeMain)
}
} else if (target.platformType in [
KotlinPlatformType.js,
KotlinPlatformType.wasm
]) {
target.compilations["main"].defaultSourceSet {
dependsOn(webMain)
}
}
}
}
}

androidx {
name = "Compose Material Navigation"
type = LibraryType.PUBLISHED_LIBRARY
mavenVersion = LibraryVersions.COMPOSE
inceptionYear = "2024"
description = "Compose Material integration with Navigation"
// samples(projectOrArtifact(":compose:material:material-navigation-samples"))
}

android {
namespace "androidx.compose.material.navigation"
}
52 changes: 52 additions & 0 deletions compose/material/material-navigation/samples/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2024 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.
*/

/**
* This file was created using the `create_project.py` script located in the
* `<AndroidX root>/development/project-creator` directory.
*
* Please use that script when creating a new project, rather than copying an existing project and
* modifying its settings.
*/
import androidx.build.LibraryType

plugins {
id("AndroidXPlugin")
id("com.android.library")
id("AndroidXComposePlugin")
id("org.jetbrains.kotlin.android")
}

dependencies {
implementation(libs.kotlinStdlib)

compileOnly(project(":annotation:annotation-sampled"))
implementation(project(":compose:foundation:foundation"))
implementation(project(":compose:material:material"))
implementation(project(":compose:material:material-navigation"))
}

androidx {
name = "Compose Material Navigation Integration Samples"
type = LibraryType.SAMPLES
mavenVersion = LibraryVersions.COMPOSE
inceptionYear = "2024"
description = "Samples for Compose Material integration with Navigation"
}

android {
namespace "androidx.compose.material.navigation.samples"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,15 @@
package androidx.compose.material.navigation

import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material.navigation.BottomSheetNavigator.Destination
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import androidx.compose.runtime.setValue
import androidx.compose.ui.util.fastForEach
Expand All @@ -44,45 +40,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.transform

/**
* The state of a [ModalBottomSheetLayout] that the [BottomSheetNavigator] drives
*
* @param sheetState The sheet state that is driven by the [BottomSheetNavigator]
*/
public class BottomSheetNavigatorSheetState(private val sheetState: ModalBottomSheetState) {
/**
* @see ModalBottomSheetState.isVisible
*/
public val isVisible: Boolean
get() = sheetState.isVisible

/**
* @see ModalBottomSheetState.currentValue
*/
public val currentValue: ModalBottomSheetValue
get() = sheetState.currentValue

/**
* @see ModalBottomSheetState.targetValue
*/
public val targetValue: ModalBottomSheetValue
get() = sheetState.targetValue
}

/**
* Create and remember a [BottomSheetNavigator]
*/
@Composable
public fun rememberBottomSheetNavigator(
animationSpec: AnimationSpec<Float> = SpringSpec()
): BottomSheetNavigator {
val sheetState = rememberModalBottomSheetState(
ModalBottomSheetValue.Hidden,
animationSpec = animationSpec
)
return remember(sheetState) { BottomSheetNavigator(sheetState) }
}

/**
* Navigator that drives a [ModalBottomSheetState] for use of [ModalBottomSheetLayout]s
* with the navigation library. Every destination using this Navigator must set a valid
Expand All @@ -103,8 +60,8 @@ public fun rememberBottomSheetNavigator(
* drive the sheet state
*/
@Navigator.Name("bottomSheet")
public class BottomSheetNavigator(
internal val sheetState: ModalBottomSheetState
public actual class BottomSheetNavigator actual constructor(
internal actual val sheetState: ModalBottomSheetState
) : Navigator<BottomSheetNavigator.Destination>() {

private var attached by mutableStateOf(false)
Expand All @@ -126,7 +83,7 @@ public class BottomSheetNavigator(
* composed before the Navigator is attached, so we specifically return an empty flow if we
* aren't attached yet.
*/
internal val transitionsInProgress: StateFlow<Set<NavBackStackEntry>>
internal actual val transitionsInProgress: StateFlow<Set<NavBackStackEntry>>
get() = if (attached) {
state.transitionsInProgress
} else {
Expand All @@ -136,14 +93,14 @@ public class BottomSheetNavigator(
/**
* Access properties of the [ModalBottomSheetLayout]'s [ModalBottomSheetState]
*/
public val navigatorSheetState: BottomSheetNavigatorSheetState =
public actual val navigatorSheetState: BottomSheetNavigatorSheetState =
BottomSheetNavigatorSheetState(sheetState)

/**
* A [Composable] function that hosts the current sheet content. This should be set as
* sheetContent of your [ModalBottomSheetLayout].
*/
internal val sheetContent: @Composable ColumnScope.() -> Unit = {
internal actual val sheetContent: @Composable ColumnScope.() -> Unit = {
val saveableStateHolder = rememberSaveableStateHolder()
val transitionsInProgressEntries by transitionsInProgress.collectAsState()

Expand Down Expand Up @@ -235,8 +192,8 @@ public class BottomSheetNavigator(
* [NavDestination] specific to [BottomSheetNavigator]
*/
@NavDestination.ClassType(Composable::class)
public class Destination(
public actual class Destination actual constructor(
navigator: BottomSheetNavigator,
internal val content: @Composable ColumnScope.(NavBackStackEntry) -> Unit
internal actual val content: @Composable ColumnScope.(NavBackStackEntry) -> Unit
) : NavDestination(navigator), FloatingWindow
}
Loading

0 comments on commit c96b59a

Please sign in to comment.