diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8fe0bc2..898fb89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,8 +38,6 @@ jobs: run: chmod +x gradlew - name: Build with Gradle run: ./gradlew build test - - name: Detekt - run: ./gradlew detekt - name: Upload API uses: actions/upload-artifact@v1 with: diff --git a/compass/api/src/main/kotlin/de/onecode/compass/api/DeepLink.kt b/compass/api/src/main/kotlin/de/onecode/compass/api/DeepLink.kt new file mode 100644 index 0000000..7619cf3 --- /dev/null +++ b/compass/api/src/main/kotlin/de/onecode/compass/api/DeepLink.kt @@ -0,0 +1,6 @@ +package de.onecode.compass.api + +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +@Repeatable +annotation class DeepLink(val schema: String, val host: String, val path: String = "") diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/Extensions.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/Extensions.kt index b3888d7..81b2d7a 100644 --- a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/Extensions.kt +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/Extensions.kt @@ -6,8 +6,11 @@ import com.google.devtools.ksp.symbol.KSAnnotation import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSType +import de.onecode.compass.api.DeepLink import de.onecode.compass.api.Destination +import de.onecode.compass.api.Parameter import de.onecode.compass.api.SubGraph +import de.onecode.compass.ksp.descriptions.DeepLinkDescription import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.ParameterDescription import de.onecode.compass.ksp.descriptions.SubGraphDescription @@ -42,8 +45,8 @@ fun KSType.asClassDeclaration(): KSClassDeclaration = ?: error("${declaration.simpleName.asString()} has to be a class, an interface or an object") fun KSAnnotation.toParameterDescription(classDeclaration: KSClassDeclaration): ParameterDescription { - val paramName = getParameterValue(ParameterDescription::name.name, classDeclaration) - val paramType = getParameterValue(ParameterDescription::type.name, classDeclaration) + val paramName = getParameterValue(Parameter::name.name, classDeclaration) + val paramType = getParameterValue(Parameter::type.name, classDeclaration) return ParameterDescription( name = paramName, @@ -52,6 +55,18 @@ fun KSAnnotation.toParameterDescription(classDeclaration: KSClassDeclaration): P ) } +fun KSAnnotation.toDeepLinkDescription(classDeclaration: KSClassDeclaration): DeepLinkDescription { + val schema = getParameterValue(DeepLink::schema.name, classDeclaration) + val host = getParameterValue(DeepLink::host.name, classDeclaration) + val path = getParameterValue(DeepLink::path.name, classDeclaration) + + return DeepLinkDescription( + schema = schema, + host = host, + path = path + ) +} + fun KSDeclaration.filterAnnotations(annotationClass: KClass): Sequence = annotations.filter { it.shortName.asString() == annotationClass.simpleName } diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DeepLinkDescription.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DeepLinkDescription.kt new file mode 100644 index 0000000..cdf34e4 --- /dev/null +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DeepLinkDescription.kt @@ -0,0 +1,7 @@ +package de.onecode.compass.ksp.descriptions + +data class DeepLinkDescription( + val schema: String, + val host: String, + val path: String, +) diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DestinationDescription.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DestinationDescription.kt index dc38988..add0d0b 100644 --- a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DestinationDescription.kt +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/descriptions/DestinationDescription.kt @@ -4,6 +4,7 @@ data class DestinationDescription( override val name: String, override val parameters: List, val navigationTargets: List, + val deepLinks: List, val isHome: Boolean, val isTop: Boolean, ) : NamedWithParameters diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/discovery/DestinationVisitor.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/discovery/DestinationVisitor.kt index f0966c8..a9ac8da 100644 --- a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/discovery/DestinationVisitor.kt +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/discovery/DestinationVisitor.kt @@ -4,6 +4,7 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSType import com.google.devtools.ksp.symbol.KSVisitorVoid import com.squareup.kotlinpoet.ksp.toClassName +import de.onecode.compass.api.DeepLink import de.onecode.compass.api.Destination import de.onecode.compass.api.Home import de.onecode.compass.api.Navigation @@ -19,6 +20,7 @@ import de.onecode.compass.ksp.getDestinationName import de.onecode.compass.ksp.getParameterValue import de.onecode.compass.ksp.getSubGraphName import de.onecode.compass.ksp.isNavigable +import de.onecode.compass.ksp.toDeepLinkDescription import de.onecode.compass.ksp.toParameterDescription class DestinationVisitor : KSVisitorVoid() { @@ -71,10 +73,16 @@ class DestinationVisitor : KSVisitorVoid() { parameterAnnotation.toParameterDescription(classDeclaration) } + val deeplinks = classDeclaration.filterAnnotations(DeepLink::class) + .map { deeplinkAnnotation -> + deeplinkAnnotation.toDeepLinkDescription(classDeclaration) + } + _destinations += DestinationDescription( name = destinationName, parameters = parameters.toList(), navigationTargets = navTargets.toList(), + deepLinks = deeplinks.toList(), isHome = isHome, isTop = isTop ) diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/CodeGeneration.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/CodeGeneration.kt index 0bcd51b..df7e5fc 100644 --- a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/CodeGeneration.kt +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/CodeGeneration.kt @@ -79,6 +79,9 @@ private fun createFileSpec(graph: GraphDescription): FileSpec.Builder { if (destinations.containsParameters() || subGraphs.hasParametrizedDestinations()) { addImport("androidx.navigation", *navigationImports) } + if (destinations.containsDeepLinks() || subGraphs.hasDestinationsWithDeepLinks()) { + addImport("androidx.navigation", "NavDeepLink") + } } return fileSpec @@ -106,7 +109,13 @@ private fun FileSpec.Builder.addParameterExtensionsOnSavedStateHandle(destinatio } private fun List.hasParametrizedDestinations(): Boolean = - any { subGraph -> subGraph.destinations.any { it.parameters.isNotEmpty() } } + any { it.destinations.containsParameters() } private fun List.containsParameters(): Boolean = any { it.parameters.isNotEmpty() } + +private fun List.hasDestinationsWithDeepLinks(): Boolean = + any { it.destinations.containsDeepLinks() } + +private fun List.containsDeepLinks(): Boolean = + any { it.deepLinks.isNotEmpty() } diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/AddComposablesBody.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/AddComposablesBody.kt index 8331a6c..3e04997 100644 --- a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/AddComposablesBody.kt +++ b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/AddComposablesBody.kt @@ -5,7 +5,9 @@ import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.buildCodeBlock import de.onecode.compass.ksp.decapitalize +import de.onecode.compass.ksp.descriptions.DeepLinkDescription import de.onecode.compass.ksp.descriptions.DestinationDescription +import de.onecode.compass.ksp.descriptions.ParameterDescription import de.onecode.compass.ksp.generator.LOCAL_NAV_HOST_CONTROLLER import de.onecode.compass.ksp.generator.contextName import de.onecode.compass.ksp.route @@ -44,14 +46,20 @@ private fun DestinationDescription.toNavigationComposableCodeBlock(): CodeBlock private fun buildComposableCodeBlock(destination: DestinationDescription, statements: CodeBlock.Builder.() -> Unit): CodeBlock = buildCodeBlock { - beginControlFlow("composable(route = %S, arguments = %L)", destination.route, navigationArgumentsCodeBlock(destination)) + val arguments = navigationArgumentsCodeBlock(destination.parameters) + val deepLinks = deepLinksCodeBlock(destination.deepLinks, destination.parameters) + beginControlFlow( + "composable(route = %S, arguments = %L, deepLinks = %L)", + destination.route, + arguments, + deepLinks + ) statements() endControlFlow() } -private fun navigationArgumentsCodeBlock(description: DestinationDescription): CodeBlock { - val parameters = description.parameters - return buildCodeBlock { +private fun navigationArgumentsCodeBlock(parameters: List): CodeBlock = + buildCodeBlock { if (parameters.isEmpty()) { addStatement("emptyList()") } else { @@ -67,4 +75,36 @@ private fun navigationArgumentsCodeBlock(description: DestinationDescription): C addStatement("listOf(%L)", blocks.joinToString()) } } + +private fun deepLinksCodeBlock(deepLinks: List, parameters: List): CodeBlock = + buildCodeBlock { + if (deepLinks.isEmpty()) { + addStatement("emptyList()") + } else { + val parametersSuffix = parameters.joinToString(separator = "/") { "{${it.name}}" } + val navDeepLink = deepLinks.map { description -> + val deepLink = description.toUri(parametersSuffix) + buildCodeBlock { + addStatement("NavDeepLink(%S)", deepLink) + } + } + + addStatement("listOf(%L)", navDeepLink.joinToString()) + } + } + +private fun DeepLinkDescription.toUri(parametersSuffix: String): String { + val uri = "${schema}://${host}" + return if (path.isBlank()) { + uri + } else { + "$uri/$path" + }.let { + if (parametersSuffix.isBlank()) { + it + } else { + "$it/$parametersSuffix" + } + } } + diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateNavigatorComposable.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposable.kt similarity index 100% rename from compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateNavigatorComposable.kt rename to compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposable.kt diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateNavigatorController.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassController.kt similarity index 100% rename from compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateNavigatorController.kt rename to compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassController.kt diff --git a/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateRememberNavigatorController.kt b/compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateRememberCompassController.kt similarity index 100% rename from compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateRememberNavigatorController.kt rename to compass/ksp/src/main/kotlin/de/onecode/compass/ksp/generator/navigation/CreateRememberCompassController.kt diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/CheckGraphStateTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/CheckGraphStateTest.kt index bf49568..061058a 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/CheckGraphStateTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/CheckGraphStateTest.kt @@ -1,28 +1,22 @@ package de.onecode.compass.ksp import com.google.common.truth.Truth.assertThat -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.GraphDescription import de.onecode.compass.ksp.descriptions.SubGraphDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows class CheckGraphStateTest { @Test fun `Fail because of multiple homes`() { - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) val graph = GraphDescription(listOf(description1, description2), emptyList()) @@ -33,19 +27,12 @@ class CheckGraphStateTest { @Test fun `Standard graph`() { - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val graph = GraphDescription(listOf(description1, description2), emptyList()) @@ -57,19 +44,11 @@ class CheckGraphStateTest { @Test fun `No home graph`() { - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val graph = GraphDescription(listOf(description1, description2), emptyList()) @@ -91,19 +70,13 @@ class CheckGraphStateTest { @Test fun `Subgraph with multiple homes`() { - val sub1 = DestinationDescription( + val sub1 = destinationDescription( name = "sub1", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) - val sub2 = DestinationDescription( + val sub2 = destinationDescription( name = "sub2", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) val sub = SubGraphDescription("sub", listOf(sub1, sub2)) val graph = GraphDescription(emptyList(), listOf(sub)) @@ -115,19 +88,11 @@ class CheckGraphStateTest { @Test fun `Subgraph with no home`() { - val sub1 = DestinationDescription( + val sub1 = destinationDescription( name = "sub1", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) - val sub2 = DestinationDescription( + val sub2 = destinationDescription( name = "sub2", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val sub = SubGraphDescription("sub", listOf(sub1, sub2)) val graph = GraphDescription(emptyList(), listOf(sub)) @@ -139,18 +104,12 @@ class CheckGraphStateTest { @Test fun `Subgraph with unallowed tob destination`() { - val sub1 = DestinationDescription( + val sub1 = destinationDescription( name = "sub1", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) - val sub2 = DestinationDescription( + val sub2 = destinationDescription( name = "sub2", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, isTop = true ) val sub = SubGraphDescription("sub", listOf(sub1, sub2)) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/discovery/GraphVisitorTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/discovery/GraphVisitorTest.kt index b212fae..0196a6b 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/discovery/GraphVisitorTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/discovery/GraphVisitorTest.kt @@ -1,15 +1,20 @@ package de.onecode.compass.ksp.discovery import com.google.common.truth.Truth.assertThat -import de.onecode.compass.ksp.descriptions.DestinationDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test class GraphVisitorTest { @Test fun `create graph description without sub graph`() { val destinations = listOf( - DestinationDescription(name = "D1", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false), - DestinationDescription(name = "D2", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + destinationDescription( + name = "D1", + isHome = true, + ), + destinationDescription( + name = "D2", + ) ) val graphVisitor = GraphVisitor(destinations) @@ -23,11 +28,21 @@ class GraphVisitorTest { @Test fun `create graph description with sub graph`() { - val s1 = DestinationDescription(name = "S1", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val s2 = DestinationDescription(name = "S2", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val s1 = destinationDescription( + name = "S1", + isHome = true, + ) + val s2 = destinationDescription( + name = "S2", + ) val destinations = listOf( - DestinationDescription(name = "D1", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false), - DestinationDescription(name = "D2", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false), + destinationDescription( + name = "D1", + isHome = true, + ), + destinationDescription( + name = "D2", + ), s1, s2 ) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/CodeGeneratorTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/CodeGeneratorTest.kt index 7810f89..0c673f1 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/CodeGeneratorTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/CodeGeneratorTest.kt @@ -1,11 +1,11 @@ package de.onecode.compass.ksp.generator import de.onecode.compass.ksp.assertGeneratedCode -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.GraphDescription import de.onecode.compass.ksp.descriptions.NavigationTarget import de.onecode.compass.ksp.descriptions.ParameterDescription -import de.onecode.compass.ksp.descriptions.SubGraphDescription +import de.onecode.compass.ksp.generator.common.destinationDescription +import de.onecode.compass.ksp.generator.common.subGraphDescription import de.onecode.compass.ksp.writeToString import org.junit.jupiter.api.Test @@ -14,19 +14,14 @@ class CodeGeneratorTest { @Test fun `Two destinations not top and no subgraph`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val graph = GraphDescription( destinations = listOf(description1, description2), @@ -135,6 +130,7 @@ class CodeGeneratorTest { val screenBuilder = ScreenBuilderImpl() screenBuilder.builder(this) composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } @@ -142,6 +138,7 @@ class CodeGeneratorTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.barComposable?.invoke(barContext(LocalNavHostController.current, it)) } @@ -205,18 +202,14 @@ class CodeGeneratorTest { @Test fun `Two destinations one top and no subgraph`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, isTop = true ) val graph = GraphDescription( @@ -341,6 +334,7 @@ class CodeGeneratorTest { val screenBuilder = ScreenBuilderImpl() screenBuilder.builder(this) composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } @@ -348,6 +342,7 @@ class CodeGeneratorTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.barComposable?.invoke(barContext(LocalNavHostController.current, it)) } @@ -411,36 +406,25 @@ class CodeGeneratorTest { @Test fun `Two destinations one top and subgraph`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, isTop = true ) - val sub1 = DestinationDescription( + val sub1 = destinationDescription( name = "sub1", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) - val sub2 = DestinationDescription( + val sub2 = destinationDescription( name = "sub1", - parameters = emptyList(), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) - val sub = SubGraphDescription("sub", listOf(sub1, sub2)) + val sub = subGraphDescription("sub", sub1, sub2) val graph = GraphDescription( destinations = listOf(description1, description2), subGraphs = listOf(sub) @@ -565,6 +549,7 @@ class CodeGeneratorTest { val screenBuilder = ScreenBuilderImpl() screenBuilder.builder(this) composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } @@ -572,6 +557,7 @@ class CodeGeneratorTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.barComposable?.invoke(barContext(LocalNavHostController.current, it)) } @@ -635,10 +621,12 @@ class CodeGeneratorTest { val screenBuilder = subScreenBuilderImpl() screenBuilder.builder(this) composable(route = "sub1", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.sub1Composable?.invoke(sub1Context(LocalNavHostController.current, it)) } composable(route = "sub1", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.sub1Composable?.invoke(sub1Context(LocalNavHostController.current, it)) } @@ -694,19 +682,13 @@ class CodeGeneratorTest { @Test fun `Two destinations no home`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), - isHome = false, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val graph = GraphDescription(listOf(description1, description2), emptyList()) @@ -738,6 +720,7 @@ class CodeGeneratorTest { public fun NavGraphBuilder.fooScreen(composable: @Composable fooContext.() -> Unit) { composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { val current = LocalNavHostController.current val context = fooContext(current, it) @@ -764,6 +747,7 @@ class CodeGeneratorTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { val current = LocalNavHostController.current val context = barContext(current, it) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/DescriptionCreator.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/DescriptionCreator.kt new file mode 100644 index 0000000..5f6f77a --- /dev/null +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/DescriptionCreator.kt @@ -0,0 +1,31 @@ +package de.onecode.compass.ksp.generator.common + +import de.onecode.compass.ksp.descriptions.DeepLinkDescription +import de.onecode.compass.ksp.descriptions.DestinationDescription +import de.onecode.compass.ksp.descriptions.NavigationTarget +import de.onecode.compass.ksp.descriptions.ParameterDescription +import de.onecode.compass.ksp.descriptions.SubGraphDescription + +@Suppress("LongParameterList") +fun destinationDescription( + name: String, + parameters: List = emptyList(), + navigationTargets: List = emptyList(), + deepLinks: List = emptyList(), + isHome: Boolean = false, + isTop: Boolean = false, +): DestinationDescription = + DestinationDescription( + name = name, + parameters = parameters, + navigationTargets = navigationTargets, + deepLinks = deepLinks, + isHome = isHome, + isTop = isTop + ) + +fun subGraphDescription(name: String, vararg descriptions: DestinationDescription): SubGraphDescription = + SubGraphDescription( + name = name, + destinations = descriptions.toList() + ) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/NavigationFunctionTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/NavigationFunctionTest.kt index 15e425a..464f011 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/NavigationFunctionTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/common/NavigationFunctionTest.kt @@ -14,7 +14,14 @@ import org.junit.jupiter.api.Test class NavigationFunctionTest { @Test fun `navigation function for Destination without parameters`() { - val description = DestinationDescription(name = "foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val description = DestinationDescription( + name = "foo", + parameters = emptyList(), + navigationTargets = emptyList(), + deepLinks = emptyList(), + isHome = false, + isTop = false + ) val navControllerParamName = "navHostController" val code = buildTestFile { diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateContextClassTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateContextClassTest.kt index 10d53fe..4193543 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateContextClassTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateContextClassTest.kt @@ -2,16 +2,18 @@ package de.onecode.compass.ksp.generator.context import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.NavigationTarget import de.onecode.compass.ksp.descriptions.ParameterDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier", "RemoveRedundantQualifierName", "CanBeParameter", "ClassName") class CreateContextClassTest { @Test fun `Destination Context with no parameters and no navigation`() { - val description = DestinationDescription("foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val description = destinationDescription( + name = "foo", + ) val code = buildTestFile { addType(createContextClass(description, "CommonContext")) @@ -37,7 +39,10 @@ class CreateContextClassTest { @Test fun `Destination Context with one parameter and no navigation`() { - val description = DestinationDescription("foo", parameters = listOf(ParameterDescription("param1", "kotlin.String")), navigationTargets = emptyList(), isHome = false, isTop = false) + val description = destinationDescription( + name = "foo", + parameters = listOf(ParameterDescription("param1", "kotlin.String")), + ) val code = buildTestFile { addType(createContextClass(description, "CommonContext")) @@ -67,12 +72,10 @@ class CreateContextClassTest { @Test fun `Destination Context with one parameter and one navigation that also has one parameter`() { - val description = DestinationDescription( - "foo", + val description = destinationDescription( + name = "foo", parameters = listOf(ParameterDescription("param1", "kotlin.String")), navigationTargets = listOf(NavigationTarget("target", listOf(ParameterDescription("targetParam1", "kotlin.Int")))), - isHome = false, - isTop = false ) val code = buildTestFile { diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateSubGraphContextTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateSubGraphContextTest.kt index 04dfbc7..f0add4c 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateSubGraphContextTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/context/CreateSubGraphContextTest.kt @@ -2,17 +2,22 @@ package de.onecode.compass.ksp.generator.context import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription -import de.onecode.compass.ksp.descriptions.SubGraphDescription +import de.onecode.compass.ksp.generator.common.destinationDescription +import de.onecode.compass.ksp.generator.common.subGraphDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier", "ClassName") class CreateSubGraphContextTest { @Test fun `SubGraph Context`() { - val description1 = DestinationDescription("foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val description2 = DestinationDescription("bar", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) - val subGraph = SubGraphDescription("sub", listOf(description1, description2)) + val description1 = destinationDescription( + name = "foo", + isHome = true, + ) + val description2 = destinationDescription( + name = "bar", + ) + val subGraph = subGraphDescription("sub", description1, description2) val code = buildTestFile { addType(createSubGraphContext(subGraph)) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposableTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposableTest.kt index db2aea1..7032c53 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposableTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassComposableTest.kt @@ -2,20 +2,17 @@ package de.onecode.compass.ksp.generator.navigation import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.ParameterDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier", "TestFunctionName") class CreateCompassComposableTest { @Test fun `Navigator with a destination without parameters`() { - val description = DestinationDescription( + val description = destinationDescription( name = "foo", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) val code = buildTestFile { @@ -48,7 +45,8 @@ class CreateCompassComposableTest { NavHost(modifier = modifier, startDestination = "foo", navController = navController) { val screenBuilder = ScreenBuilderImpl() screenBuilder.builder(this) - composable(route = "foo", arguments = emptyList() + composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } @@ -61,12 +59,10 @@ class CreateCompassComposableTest { @Test fun `Navigator with a destination with a parameter`() { - val description = DestinationDescription( + val description = destinationDescription( name = "foo", parameters = listOf(ParameterDescription("param1", "kotlin.Int")), - navigationTargets = emptyList(), isHome = true, - isTop = false ) val code = buildTestFile { @@ -103,6 +99,7 @@ class CreateCompassComposableTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassControllerTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassControllerTest.kt index cd5242c..75202e8 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassControllerTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateCompassControllerTest.kt @@ -2,21 +2,18 @@ package de.onecode.compass.ksp.generator.navigation import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.NavigationTarget import de.onecode.compass.ksp.descriptions.ParameterDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier", "RemoveRedundantQualifierName", "TestFunctionName") class CreateCompassControllerTest { @Test fun `CompassController with one Destination no top`() { - val description = DestinationDescription( + val description = destinationDescription( name = "foo", - parameters = emptyList(), - navigationTargets = emptyList(), isHome = true, - isTop = false ) val code = buildTestFile { @@ -89,19 +86,14 @@ class CreateCompassControllerTest { @Test fun `CompassController with two Destination no top`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val code = buildTestFile { @@ -174,18 +166,14 @@ class CreateCompassControllerTest { @Test fun `CompassController with two Destination and one top`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, isTop = true ) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateSubGraphFunctionTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateSubGraphFunctionTest.kt index 4a878bb..9581e3e 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateSubGraphFunctionTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/navigation/CreateSubGraphFunctionTest.kt @@ -2,10 +2,11 @@ package de.onecode.compass.ksp.generator.navigation import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.NavigationTarget import de.onecode.compass.ksp.descriptions.ParameterDescription import de.onecode.compass.ksp.descriptions.SubGraphDescription +import de.onecode.compass.ksp.generator.common.destinationDescription +import de.onecode.compass.ksp.generator.common.subGraphDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier") @@ -13,19 +14,14 @@ class CreateSubGraphFunctionTest { @Test fun `SuGraph function with two destinations`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description1 = DestinationDescription( + val description1 = destinationDescription( name = "foo", - parameters = emptyList(), navigationTargets = listOf(NavigationTarget("bar", listOf(param1))), isHome = true, - isTop = false ) - val description2 = DestinationDescription( + val description2 = destinationDescription( name = "bar", parameters = listOf(param1), - navigationTargets = emptyList(), - isHome = false, - isTop = false ) val subGraph = SubGraphDescription( name = "sub", @@ -51,6 +47,7 @@ class CreateSubGraphFunctionTest { val screenBuilder = subScreenBuilderImpl() screenBuilder.builder(this) composable(route = "foo", arguments = emptyList() + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } @@ -58,6 +55,7 @@ class CreateSubGraphFunctionTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.barComposable?.invoke(barContext(LocalNavHostController.current, it)) } @@ -70,8 +68,12 @@ class CreateSubGraphFunctionTest { @Test fun `SuGraph function with a home with parameters`() { val param1 = ParameterDescription("param1", "kotlin.Int") - val description = DestinationDescription("foo", parameters = listOf(param1), navigationTargets = emptyList(), isHome = true, isTop = false) - val subGraph = SubGraphDescription("sub", listOf(description)) + val description = destinationDescription( + name = "foo", + parameters = listOf(param1), + isHome = true, + ) + val subGraph = subGraphDescription("sub", description) val code = buildTestFile { addFunction(createSubGraphFunction(subGraph)) @@ -95,6 +97,7 @@ class CreateSubGraphFunctionTest { type = NavType.IntType } ) + , deepLinks = emptyList() ) { screenBuilder.fooComposable?.invoke(fooContext(LocalNavHostController.current, it)) } diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateScreenBuilderTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateScreenBuilderTest.kt index 007a909..456e374 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateScreenBuilderTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateScreenBuilderTest.kt @@ -2,15 +2,20 @@ package de.onecode.compass.ksp.generator.screenbuilder import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription +import de.onecode.compass.ksp.generator.common.destinationDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier") class CreateScreenBuilderTest { @Test fun `ScreenBuilder interface`() { - val description1 = DestinationDescription(name = "foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val description2 = DestinationDescription(name = "bar", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val description1 = destinationDescription( + name = "foo", + isHome = true, + ) + val description2 = destinationDescription( + name = "bar", + ) val code = buildTestFile { addType(createScreenBuilderInterface(listOf(description1, description2))) @@ -38,8 +43,13 @@ class CreateScreenBuilderTest { @Test fun `ScreenBuilder implementation`() { - val description1 = DestinationDescription(name = "foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val description2 = DestinationDescription(name = "bar", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val description1 = destinationDescription( + name = "foo", + isHome = true, + ) + val description2 = destinationDescription( + name = "bar", + ) val code = buildTestFile { addType(createScreenBuilderImplementation(listOf(description1, description2))) diff --git a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateSubGraphBuilderTest.kt b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateSubGraphBuilderTest.kt index 58b5b13..8fd36c4 100644 --- a/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateSubGraphBuilderTest.kt +++ b/compass/ksp/src/test/kotlin/de/onecode/compass/ksp/generator/screenbuilder/CreateSubGraphBuilderTest.kt @@ -2,17 +2,23 @@ package de.onecode.compass.ksp.generator.screenbuilder import de.onecode.compass.ksp.assertGeneratedCode import de.onecode.compass.ksp.buildTestFile -import de.onecode.compass.ksp.descriptions.DestinationDescription import de.onecode.compass.ksp.descriptions.SubGraphDescription +import de.onecode.compass.ksp.generator.common.destinationDescription +import de.onecode.compass.ksp.generator.common.subGraphDescription import org.junit.jupiter.api.Test @Suppress("RedundantVisibilityModifier", "ClassName") class CreateSubGraphBuilderTest { @Test fun `SubGraphBuilder interface`() { - val description1 = DestinationDescription(name = "foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val description2 = DestinationDescription(name = "bar", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) - val subGraph = SubGraphDescription(name = "sub", listOf(description1, description2)) + val description1 = destinationDescription( + name = "foo", + isHome = true, + ) + val description2 = destinationDescription( + name = "bar", + ) + val subGraph = subGraphDescription(name = "sub", description1, description2) val code = buildTestFile { addType(createSubGraphBuilderInterface(subGraph)) @@ -40,8 +46,13 @@ class CreateSubGraphBuilderTest { @Test fun `ScreenBuilder implementation`() { - val description1 = DestinationDescription(name = "foo", parameters = emptyList(), navigationTargets = emptyList(), isHome = true, isTop = false) - val description2 = DestinationDescription(name = "bar", parameters = emptyList(), navigationTargets = emptyList(), isHome = false, isTop = false) + val description1 = destinationDescription( + name = "foo", + isHome = true, + ) + val description2 = destinationDescription( + name = "bar", + ) val subGraph = SubGraphDescription(name = "sub", listOf(description1, description2)) val code = buildTestFile { diff --git a/demo/app/src/main/AndroidManifest.xml b/demo/app/src/main/AndroidManifest.xml index 2996a93..a06b02f 100644 --- a/demo/app/src/main/AndroidManifest.xml +++ b/demo/app/src/main/AndroidManifest.xml @@ -22,6 +22,17 @@ + + + + + + + + diff --git a/demo/app/src/main/kotlin/de/onecode/compass/demo/details/DetailsDescription.kt b/demo/app/src/main/kotlin/de/onecode/compass/demo/details/DetailsDescription.kt index d4200eb..6f37993 100644 --- a/demo/app/src/main/kotlin/de/onecode/compass/demo/details/DetailsDescription.kt +++ b/demo/app/src/main/kotlin/de/onecode/compass/demo/details/DetailsDescription.kt @@ -1,5 +1,6 @@ package de.onecode.compass.demo.details +import de.onecode.compass.api.DeepLink import de.onecode.compass.api.Destination import de.onecode.compass.api.Navigation import de.onecode.compass.api.Parameter @@ -10,4 +11,5 @@ import de.onecode.compass.demo.wizard.WizardSubGraph @Destination(name = "Details") @Parameter(name = "myParam", type = Int::class) @Navigation(to = WizardSubGraph::class) +@DeepLink(schema = "compass", host = "demo", path = "details") object DetailsDescription