Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement hierarchy helper functions #190

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ fun String.sanitizePackageName(): String {
}

private val humps = "(?<=.)(?=\\p{Upper})".toRegex()
fun String.toSnakeCase() = replace(humps, "_").lowercase(Locale.US)
fun String.toSnakeCase() = replace(humps, "_").lowercase(Locale.US)

fun String.asNavGraphName(): String {
var lower = this.lowercase(Locale.US)
lower = lower.replace("navgraph", "")
return this.substring(0, lower.length).replaceFirstChar { it.lowercase() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ data class NavGraphGeneratingParams(
val destinations: List<GeneratedDestination>,
val startRouteFieldName: String,
val nestedNavGraphRoutes: List<String>,
val requireOptInAnnotationTypes: Set<Importable>
val requireOptInAnnotationTypes: Set<Importable>,
val parent: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.ramcosta.composedestinations.codegen.templates.core.setOfImportable
const val DESTINATION_NAME = "[DESTINATION_NAME]"
const val BASE_ROUTE = "[ROUTE_ID]"
const val COMPOSED_ROUTE = "[COMPOSED_ROUTE]"
const val DESTINATION_PARENT = "[DESTINATION_PARENT]"
const val NAV_ARGUMENTS = "[NAV_ARGUMENTS]"
const val DEEP_LINKS = "[DEEP_LINKS]"
const val DESTINATION_STYLE = "[DESTINATION_STYLE]"
Expand Down Expand Up @@ -47,6 +48,8 @@ ${REQUIRE_OPT_IN_ANNOTATIONS_PLACEHOLDER}object $DESTINATION_NAME : $SUPERTYPE {
override val baseRoute = "$BASE_ROUTE"

override val route = $COMPOSED_ROUTE

override val parent = $DESTINATION_PARENT
$NAV_ARGUMENTS$DEEP_LINKS$DESTINATION_STYLE
@Composable
override fun DestinationScope<$NAV_ARGS_CLASS_SIMPLE_NAME>.Content(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.ramcosta.composedestinations.codegen.templates.core.FileTemplate
import com.ramcosta.composedestinations.codegen.templates.core.setOfImportable

const val NAV_GRAPHS_PLACEHOLDER = "[NAV_GRAPHS_PLACEHOLDER]"
const val NAV_GRAPHS_LIST_PLACEHOLDER = "[NAV_GRAPHS_LIST_PLACEHOLDER]"

val navGraphsObjectTemplate = FileTemplate(
packageStatement = "package $codeGenBasePackageName",
Expand All @@ -24,6 +25,8 @@ val navGraphsObjectTemplate = FileTemplate(
object $GENERATED_NAV_GRAPHS_OBJECT {

$NAV_GRAPHS_PLACEHOLDER

$NAV_GRAPHS_LIST_PLACEHOLDER
}
""".trimIndent()
)
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,27 @@ data class $GENERATED_NAV_GRAPH(
override val route: String,
override val startRoute: Route,
val destinations: List<$typeAliasDestination>,
override val nestedNavGraphs: List<$GENERATED_NAV_GRAPH> = emptyList()
override val nestedNavGraphs: List<$GENERATED_NAV_GRAPH> = emptyList(),
override val parent: String?
): $CORE_NAV_GRAPH_SPEC {
override val destinationsByRoute: Map<String, $typeAliasDestination> = destinations.associateBy { it.route }
}

val DestinationSpec<*>.parent: NavGraph
get() {
val parent = NavGraphs.all.find {
it.destinations.contains(this)
}

return parent
?: throw InvalidObjectException("The calling object should always have a parent!")
}

val $CORE_NAV_GRAPH_SPEC.parent: NavGraph?
get() = NavGraphs.all.find {
it.nestedNavGraphs.contains(this)
}

/**
* If this [Route] is a [$typeAliasDestination], returns it
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class SingleDestinationWriter(
.replace(BASE_ROUTE, destination.cleanRoute)
.replace(NAV_ARGS_CLASS_SIMPLE_NAME, navArgsDataClassName())
.replace(COMPOSED_ROUTE, constructRouteFieldCode())
.replace(DESTINATION_PARENT, parentNavGraph())
.replace(NAV_ARGUMENTS, navArgumentsDeclarationCode())
.replace(DEEP_LINKS, deepLinksDeclarationCode())
.replace(DESTINATION_STYLE, destinationStyle())
Expand Down Expand Up @@ -353,6 +354,30 @@ class SingleDestinationWriter(
).write()
}

private fun parentNavGraph(): String {
return when (val navGraph = destination.navGraphInfo) {
is NavGraphInfo.Legacy -> {
// Get the NavGraph object from its route
importableHelper.addAndGetPlaceholder(
Importable(
navGraph.navGraphRoute,
"$codeGenBasePackageName.$GENERATED_NAV_GRAPHS_OBJECT.${navGraph.navGraphRoute}"
)
)
}
is NavGraphInfo.AnnotatedSource -> {
// Get the NavGraph object from its route too
navGraph.graphType.toString()
importableHelper.addAndGetPlaceholder(
Importable(
navGraph.graphType.simpleName.asNavGraphName(),
"$codeGenBasePackageName.$GENERATED_NAV_GRAPHS_OBJECT.${navGraph.graphType.simpleName.asNavGraphName()}"
)
)
}
}
}

private fun navArgumentsDeclarationCode(): String {
val code = StringBuilder()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import com.ramcosta.composedestinations.codegen.model.GeneratedDestination
import com.ramcosta.composedestinations.codegen.model.Importable
import com.ramcosta.composedestinations.codegen.model.NavGraphGeneratingParams
import com.ramcosta.composedestinations.codegen.model.NavGraphInfo
import com.ramcosta.composedestinations.codegen.templates.NAV_GRAPHS_LIST_PLACEHOLDER
import com.ramcosta.composedestinations.codegen.templates.NAV_GRAPHS_PLACEHOLDER
import com.ramcosta.composedestinations.codegen.templates.navGraphsObjectTemplate
import com.ramcosta.composedestinations.codegen.writers.helpers.ImportableHelper
import com.ramcosta.composedestinations.codegen.writers.helpers.writeSourceFile
import java.util.Collections.addAll

class LegacyNavGraphsSingleObjectWriter(
private val codeGenerator: CodeOutputStreamMaker,
Expand All @@ -31,6 +33,7 @@ class LegacyNavGraphsSingleObjectWriter(
importableHelper = importableHelper,
sourceCode = navGraphsObjectTemplate.sourceCode
.replace(NAV_GRAPHS_PLACEHOLDER, navGraphsDeclaration(navGraphsParams))
.replace(NAV_GRAPHS_LIST_PLACEHOLDER, navGraphsListDeclaration(navGraphsParams))
)

return navGraphsParams
Expand Down Expand Up @@ -61,13 +64,16 @@ class LegacyNavGraphsSingleObjectWriter(
val nestedGraphsAnchor = "[NESTED_GRAPHS]"
val requireOptInAnnotationsAnchor = "[REQUIRE_OPT_IN_ANNOTATIONS_ANCHOR]"

val parent = if (route == "root") "null" else "\"${navGraphParams.parent}\""

return """
| ${requireOptInAnnotationsAnchor}val ${navGraphFieldName(route)} = $GENERATED_NAV_GRAPH(
| route = "$route",
| startRoute = ${startRouteFieldName},
| destinations = listOf(
| $destinationsAnchor
| )${if (nestedNavGraphRoutes.isEmpty()) "" else ",\n|\t\t$nestedGraphsAnchor"}
| )${if (nestedNavGraphRoutes.isEmpty()) "" else ",\n|\t\t$nestedGraphsAnchor"},
| parent = $parent
| )
""".trimMargin()
.replace(destinationsAnchor, destinationsInsideList(destinations))
Expand All @@ -79,6 +85,19 @@ class LegacyNavGraphsSingleObjectWriter(

}

private fun navGraphsListDeclaration(navGraphsParams: List<NavGraphGeneratingParams>): String {
val navGraphsAnchor = "[NAV_GRAPHS]"
val navGraphFieldNames = navGraphsParams.joinToString(",\n\t\t") {
navGraphFieldName(it.route)
}
return """
| val all: List<$GENERATED_NAV_GRAPH> = listOf(
| $navGraphsAnchor
| )
""".trimMargin()
.replace(navGraphsAnchor, navGraphFieldNames)
}

private fun requireOptInAnnotations(navGraphRequireOptInImportables: Set<Importable>): String {
val code = StringBuilder()

Expand Down Expand Up @@ -139,7 +158,8 @@ class LegacyNavGraphsSingleObjectWriter(
destinations = it.value,
startRouteFieldName = legacyStartingDestination(navGraphRoute, it.value),
nestedNavGraphRoutes = emptyList(),
requireOptInAnnotationTypes = requireOptInClassTypes
requireOptInAnnotationTypes = requireOptInClassTypes,
parent = it.key
)
)
}
Expand All @@ -152,7 +172,8 @@ class LegacyNavGraphsSingleObjectWriter(
nestedNavGraphRoutes = nestedNavGraphs,
requireOptInAnnotationTypes = rootDestinations.orEmpty()
.requireOptInAnnotationClassTypes()
.apply { addAll(nestedNavGraphsRequireOptInAnnotations) }
.apply { addAll(nestedNavGraphsRequireOptInAnnotations) },
parent = null
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.ramcosta.composedestinations.codegen.commons.*
import com.ramcosta.composedestinations.codegen.facades.CodeOutputStreamMaker
import com.ramcosta.composedestinations.codegen.facades.Logger
import com.ramcosta.composedestinations.codegen.model.*
import com.ramcosta.composedestinations.codegen.templates.NAV_GRAPHS_LIST_PLACEHOLDER
import com.ramcosta.composedestinations.codegen.templates.NAV_GRAPHS_PLACEHOLDER
import com.ramcosta.composedestinations.codegen.templates.navGraphsObjectTemplate
import com.ramcosta.composedestinations.codegen.writers.helpers.ImportableHelper
Expand Down Expand Up @@ -65,6 +66,7 @@ class NavGraphsSingleObjectWriter(
addAll(destinationsByNavGraphParams[it]!!.requireOptInAnnotationClassTypes())
}
},
parent = rawGraph.parent?.simpleName?.asNavGraphName()
)
}

Expand All @@ -86,6 +88,7 @@ class NavGraphsSingleObjectWriter(
importableHelper = importableHelper,
sourceCode = navGraphsObjectTemplate.sourceCode
.replace(NAV_GRAPHS_PLACEHOLDER, navGraphsDeclaration(orderedNavGraphGenParams))
.replace(NAV_GRAPHS_LIST_PLACEHOLDER, navGraphsListDeclaration(orderedNavGraphGenParams))

)
}
Expand All @@ -112,13 +115,16 @@ class NavGraphsSingleObjectWriter(
val nestedGraphsAnchor = "[NESTED_GRAPHS]"
val requireOptInAnnotationsAnchor = "[REQUIRE_OPT_IN_ANNOTATIONS_ANCHOR]"

val parent = if (route == "root") "null" else "\"${navGraphParams.parent}\""

return """
| ${requireOptInAnnotationsAnchor}val ${navGraphFieldName(route)} = $GENERATED_NAV_GRAPH(
| route = "$route",
| startRoute = ${startRouteFieldName},
| destinations = listOf(
| $destinationsAnchor
| )${if (nestedNavGraphRoutes.isEmpty()) "" else ",\n|\t\t$nestedGraphsAnchor"}
| )${if (nestedNavGraphRoutes.isEmpty()) "" else ",\n|\t\t$nestedGraphsAnchor"},
| parent = $parent
| )
""".trimMargin()
.replace(destinationsAnchor, destinationsInsideList(destinations))
Expand All @@ -130,6 +136,19 @@ class NavGraphsSingleObjectWriter(

}

private fun navGraphsListDeclaration(navGraphsParams: List<NavGraphGeneratingParams>): String {
val navGraphsAnchor = "[NAV_GRAPHS]"
val navGraphFieldNames = navGraphsParams.joinToString(",\n\t\t") {
navGraphFieldName(it.route)
}
return """
| val all: List<$GENERATED_NAV_GRAPH> = listOf(
| $navGraphsAnchor
| )
""".trimMargin()
.replace(navGraphsAnchor, navGraphFieldNames)
}

private fun destinationsInsideList(destinations: List<GeneratedDestination>): String {
val code = StringBuilder()
destinations.forEachIndexed { i, it ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ infix fun <T> DestinationSpec<T>.routedIn(navGraph: NavGraphSpec): DestinationSp
override val route = "${navGraph.route}/${[email protected]}"

override val originalDestination = [email protected]

override val parent: NavGraphSpec = navGraph
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ interface DestinationSpec<T> : Route {
*/
val deepLinks: List<NavDeepLink> get() = emptyList()

/**
* The parent [NavGraph][NavGraphSpec] of the current destination
*/
val parent: NavGraphSpec

/**
* Style of this destination. It can be one of:
* - [DestinationStyle.Default]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ interface NavGraphSpec: Direction, Route {
*/
val startRoute: Route

/**
* The parent route of the current NavGraph if any
*/
val parent: String?

/**
* All destinations which belong to this navigation graph
* by their route
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.spec.DestinationSpec
import com.ramcosta.samples.playground.R
import com.ramcosta.samples.playground.ui.screens.NavGraph
import com.ramcosta.samples.playground.ui.screens.NavGraphs
import com.ramcosta.samples.playground.ui.screens.destinations.*
import java.io.InvalidObjectException

@Composable
fun DirectionDestination.DrawerContent(
Expand Down Expand Up @@ -55,4 +59,13 @@ val Destination.title
TestScreenDestination -> null
TestScreen2Destination -> null
}
}

val DestinationSpec<*>.parent: NavGraph
get() {
val parent = NavGraphs.all.find {
it.destinations.contains(this)
}

return parent ?: throw InvalidObjectException("The calling object should always have a parent!")
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ramcosta.samples.playground.ui.screens.settings

import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
Expand All @@ -9,12 +10,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationSpec
import com.ramcosta.composedestinations.spec.DestinationStyle
import com.ramcosta.composedestinations.spec.NavGraphSpec
import com.ramcosta.samples.playground.commons.SettingsNavGraph
import com.ramcosta.samples.playground.commons.findDestinationParentNavGraph
import com.ramcosta.samples.playground.commons.requireTitle
import com.ramcosta.samples.playground.ui.screens.destinations.ThemeSettingsDestination
import com.ramcosta.samples.playground.ui.screens.profile.SerializableExampleWithNavTypeSerializer
Expand All @@ -26,6 +31,10 @@ fun ColumnScope.ThemeSettings(
viewModel: SettingsViewModel,
resultNavigator: ResultBackNavigator<SerializableExampleWithNavTypeSerializer>
) {
val context = LocalContext.current

Toast.makeText(context, "Hierarchy: ${ThemeSettingsDestination.findDestinationParentNavGraph()}", Toast.LENGTH_LONG).show()

Box(
Modifier
.fillMaxWidth()
Expand Down
Loading