Last active
October 3, 2024 02:37
-
-
Save jimlyas/c5dd09c69066ac8e022558de165ce8b6 to your computer and use it in GitHub Desktop.
reflection-navigation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Inside NavHost | |
composable<SomeProfile>( | |
typeMap = mapOf( | |
typeOf<Account>() to NavType.CustomNavType | |
) | |
) { | |
// no TypeMap | |
val arg = it.toRoute<SomeProfile>() | |
// Your Composable Screen | |
} | |
// Inside ViewModel | |
// TypeMap is defined again | |
val arg = savedStateHandle.toRoute<SomeProfile>( | |
typeOf<Account>() to NavType.CustomNavType | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
implementation(libs.compose.navigation) | |
implementation(libs.gson) | |
implementation(kotlin("reflect")) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inline fun <reified destination : Any> SavedStateHandle.getArg(): destination? = try { | |
destination::class.primaryConstructor?.callBy( | |
destination::class.primaryConstructor?.parameters?.associate { parameter -> | |
parameter to parameter.getValueFrom(this) | |
}.orEmpty() | |
) | |
} catch (t: Throwable) { | |
null | |
} | |
inline fun <reified destinationClass : Any> NavBackStackEntry.getArg(): destinationClass? = try { | |
destinationClass::class.primaryConstructor?.callBy( | |
destinationClass::class.primaryConstructor?.parameters?.associate { parameter -> | |
parameter to parameter.getValueFrom(this.arguments ?: Bundle()) | |
}.orEmpty() | |
) | |
} catch (t: Throwable) { | |
null | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ** Register route to NavGraph | |
// Before | |
composable( | |
route = "somehow.this.works", | |
arguments = listOf( | |
navArgument("id") { | |
type = NavType.IntType | |
nullable = false | |
}, | |
navArgument("name") { | |
type = NavType.StringType | |
nullable = false | |
} | |
) | |
) { | |
// Your composable | |
} | |
//After | |
@Serializer | |
data class Profile(val id : int, val name : String) | |
composable<Profile> { | |
// Your composable | |
} | |
// ** Navigating | |
// Before | |
navController.navigate("somehow.this.works?id=1&name=Something") | |
// After | |
navController.navigate(Profile(1, "Something")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[versions] | |
compose-navigation = "2.8.0" | |
gson = "2.10.1" | |
kotlin = "1.9.10" | |
reflect = "0.1.0" | |
[libraries] | |
compose-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "compose-navigation" } | |
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } | |
reflect-nav = { group = "io.github.jimlyas", name = "reflection-navigation", version.ref = "reflect" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// In NavHost | |
composeRoute<SomeProfile> { | |
val args = it.getArg<SomeProfile>() | |
} | |
// In ViewModel | |
val args = savedStateHandler.getArg<SomeProfile>() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ReflectiveRoute | |
data class SomeProfile(val id: Int, val name: String, val account: Account) | |
data class Account(val currency: String, val balance: BigDecimal) | |
// Inside NavHost | |
composeRoute<SomeProfile> { | |
// Your Composable Screen | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is your route | |
val route = "somehow.this.works" | |
// your Arguments | |
val param1 = "yourParam" | |
val param2 = "yourOtherParam" | |
// need to declare your NavType for each arguments | |
// need to declare if the param nullable | |
val arguments = listOf( | |
navArgument(param1) { | |
type = NavType.StringType | |
nullable = true | |
}, | |
navArgument(param2) { | |
type = NavType.IntType | |
nullable = false | |
} | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inline fun <reified routeClass : Any> NavGraphBuilder.composeRoute( | |
deepLinks: List<NavDeepLink> = emptyList(), | |
noinline enterTransition: | |
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards | |
EnterTransition?)? = null, | |
noinline exitTransition: | |
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards | |
ExitTransition?)? = null, | |
noinline popEnterTransition: | |
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards | |
EnterTransition?)? = enterTransition, | |
noinline popExitTransition: | |
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards | |
ExitTransition?)? = exitTransition, | |
noinline sizeTransform: | |
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards | |
SizeTransform?)? = null, | |
noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit | |
) { | |
val routeKClass = routeClass::class | |
val args = routeKClass.primaryConstructor?.parameters?.map { param -> | |
navArgument(param.name.orEmpty()) { | |
type = param.toNavType() | |
nullable = param.type.isMarkedNullable | |
} | |
}.orEmpty() | |
val routeName = buildString { | |
append(routeKClass.asRouteName()) | |
append(QUESTION_MARK) | |
args.map { it.name }.forEach { s -> append("$s={$s}&") } | |
deleteAt(lastIndex) | |
} | |
composable( | |
route = routeName, | |
arguments = args, | |
deepLinks = deepLinks, | |
enterTransition = enterTransition, | |
exitTransition = exitTransition, | |
popEnterTransition = popEnterTransition, | |
popExitTransition = popExitTransition, | |
sizeTransform = sizeTransform, | |
content = content | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
composable<SomeProfile>( | |
typeMap = mapOf(typeOf<Account>() to NavType.CustomNavType) | |
) { | |
// Your composable function | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Serializable | |
data class SomeProfile(val id: Int, val name: String, val account: Account) | |
@Serializable | |
data class Account(val currency: String, val balance: @Contextual BigDecimal) | |
fun NavGraphBuilder.someRoute() { | |
composable<SomeProfile> { SomeScreen() } | |
} | |
@Composable | |
internal fun SomeScreen() { | |
Text(text = "Still Trying") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment