Skip to content

Commit

Permalink
Typesafe navigation in Phone samples (#2224)
Browse files Browse the repository at this point in the history
  • Loading branch information
yschimke authored May 3, 2024
1 parent a986fc4 commit d892aca
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 81 deletions.
4 changes: 4 additions & 0 deletions ai/sample/phone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins {
kotlin("android")
id("com.google.devtools.ksp")
id("dagger.hilt.android.plugin")
kotlin("plugin.serialization")
}

android {
Expand Down Expand Up @@ -104,6 +105,7 @@ dependencies {
implementation(libs.dagger.hiltandroid)
ksp(libs.dagger.hiltandroidcompiler)
implementation(libs.hilt.navigationcompose)
implementation(libs.androidx.navigation.compose)

implementation(projects.datalayer.core)
implementation(projects.datalayer.grpc)
Expand All @@ -124,6 +126,8 @@ dependencies {
implementation(libs.playservices.wearable)
implementation(libs.androidx.lifecycle.service)

implementation(libs.kotlinx.serialization.core)

testImplementation(libs.junit)
testImplementation(libs.robolectric)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable

@Composable
fun PhoneApp(
Expand All @@ -30,13 +31,14 @@ fun PhoneApp(
) {
NavHost(
modifier = modifier,
startDestination = "Home",
startDestination = Home,
navController = navController,
) {
composable(
route = "Home",
) {
composable<Home> {
StatusScreen()
}
}
}

@Serializable
object Home
4 changes: 4 additions & 0 deletions ai/sample/wear-prompt-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins {
kotlin("android")
id("com.google.devtools.ksp")
id("dagger.hilt.android.plugin")
kotlin("plugin.serialization")
}

android {
Expand Down Expand Up @@ -119,6 +120,9 @@ dependencies {
implementation(libs.wearcompose.material)
implementation(libs.wearcompose.foundation)
implementation(libs.wearcompose.navigation)
implementation(libs.androidx.navigation.runtime)

implementation(libs.kotlinx.serialization.core)

implementation(libs.mikepenz.markdown)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

package com.google.android.horologist.ai.sample.wear.prompt

sealed class Screen(
val route: String,
) {
object PromptScreen : Screen("prompt")
object SettingsScreen : Screen("settings")
}
import kotlinx.serialization.Serializable

@Serializable
object Prompt

@Serializable
object Settings
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ package com.google.android.horologist.ai.sample.wear.prompt
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.wear.compose.navigation.SwipeDismissableNavHost
import androidx.wear.compose.navigation.composable
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
import androidx.wear.compose.ui.tooling.preview.WearPreviewLargeRound
import androidx.wear.compose.ui.tooling.preview.WearPreviewSmallRound
import com.google.android.horologist.ai.sample.wear.prompt.nav.SwipeDismissableNavHost
import com.google.android.horologist.ai.sample.wear.prompt.nav.composable
import com.google.android.horologist.ai.sample.wear.prompt.prompt.SamplePromptScreen
import com.google.android.horologist.ai.sample.wear.prompt.settings.SettingsScreen
import com.google.android.horologist.compose.layout.AppScaffold
Expand All @@ -35,19 +35,15 @@ fun WearApp(
) {
AppScaffold(modifier = modifier) {
SwipeDismissableNavHost(
startDestination = Screen.PromptScreen.route,
startDestination = Prompt,
navController = navController,
) {
composable(
route = Screen.PromptScreen.route,
) {
composable<Prompt> {
SamplePromptScreen(
onSettingsClick = { navController.navigate(Screen.SettingsScreen.route) },
onSettingsClick = { navController.navigate(Settings) },
)
}
composable(
route = Screen.SettingsScreen.route,
) {
composable<Settings> {
SettingsScreen()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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
*
* https://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.google.android.horologist.ai.sample.wear.prompt.nav

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink
import androidx.navigation.NavDestinationBuilder
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.createGraph
import androidx.navigation.get
import androidx.wear.compose.navigation.SwipeDismissableNavHostState
import androidx.wear.compose.navigation.WearNavigator
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
import kotlin.reflect.KClass
import kotlin.reflect.KType

@Composable
public fun SwipeDismissableNavHost(
navController: NavHostController,
startDestination: Any,
modifier: Modifier = Modifier,
userSwipeEnabled: Boolean = true,
state: SwipeDismissableNavHostState = rememberSwipeDismissableNavHostState(),
route: KClass<*>? = null,
builder: NavGraphBuilder.() -> Unit,
) = androidx.wear.compose.navigation.SwipeDismissableNavHost(
navController,
remember(route, startDestination, builder) {
navController.createGraph(startDestination = startDestination, route = route, builder = builder)
},
modifier,
userSwipeEnabled,
state = state,
)

public inline fun <reified T : Any> NavGraphBuilder.composable(
typeMap: Map<KType, @JvmSuppressWildcards NavType<*>> = emptyMap(),
deepLinks: List<NavDeepLink> = emptyList(),
noinline content: @Composable (NavBackStackEntry) -> Unit,
) {
destination(
WearComposeNavigatorDestinationBuilder(
wearNavigator = provider[WearNavigator::class],
route = T::class,
typeMap = typeMap,
content = content,
).apply {
deepLinks.forEach { deepLink ->
deepLink(deepLink)
}
},
)
}

class WearComposeNavigatorDestinationBuilder(
val wearNavigator: WearNavigator,
route: KClass<*>,
typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>,
private val content: @Composable (NavBackStackEntry) -> Unit,
) : NavDestinationBuilder<WearNavigator.Destination>(wearNavigator, route, typeMap) {

override fun instantiateDestination(): WearNavigator.Destination {
return WearNavigator.Destination(wearNavigator, content)
}
}
3 changes: 3 additions & 0 deletions auth/sample/phone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
plugins {
id("com.android.application")
kotlin("android")
kotlin("plugin.serialization")
}

android {
Expand Down Expand Up @@ -110,6 +111,8 @@ dependencies {
implementation(libs.compose.material3)
implementation(libs.playservices.wearable)
implementation(libs.androidx.lifecycle.service)
implementation(libs.androidx.navigation.compose)
implementation(libs.kotlinx.serialization.core)

testImplementation(libs.junit)
testImplementation(libs.robolectric)
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ plugins {
alias(libs.plugins.metalavaGradle) apply false
alias(libs.plugins.dependencyAnalysis)
alias(libs.plugins.roborazzi) apply false
alias(libs.plugins.kotlinx.serialization) apply false
}

apply(plugin = "org.jetbrains.dokka")
Expand Down
3 changes: 3 additions & 0 deletions datalayer/sample/phone/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins {
id("com.google.devtools.ksp")
id("dagger.hilt.android.plugin")
kotlin("android")
kotlin("plugin.serialization")
}

android {
Expand Down Expand Up @@ -116,6 +117,8 @@ dependencies {
implementation(libs.androidx.navigation.compose)
implementation(libs.compose.material.iconscore)
implementation(libs.compose.material.iconsext)
implementation(libs.androidx.navigation.compose)
implementation(libs.kotlinx.serialization.core)

implementation(libs.dagger.hiltandroid)
ksp(libs.dagger.hiltandroidcompiler)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 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
*
* https://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.google.android.horologist.datalayer.sample.screens

import kotlinx.serialization.Serializable

@Serializable
object Menu

@Serializable
object AppHelperNodes

@Serializable
object AppHelperNodesListener

@Serializable
object InstallAppPromptDemo

@Serializable
object ReEngagePromptDemo

@Serializable
object SignInPromptDemo

@Serializable
object InstallTilePromptDemo

@Serializable
object InstallAppCustomPromptDemo

@Serializable
object ReEngageCustomPromptDemo

@Serializable
object SignInCustomPromptDemo

@Serializable
object InstallTileCustomPromptDemo

@Serializable
object Counter

This file was deleted.

Loading

0 comments on commit d892aca

Please sign in to comment.