|
import androidx.navigation.NavBackStackEntry |
|
import androidx.navigation.NavType |
|
import androidx.navigation.navArgument |
|
|
|
enum class ArgumentType { |
|
String, Int, Boolean, BooleanOptional; |
|
|
|
fun toNavType() = when (this) { |
|
String -> NavType.StringType |
|
Int -> NavType.IntType |
|
Boolean -> NavType.BoolType |
|
BooleanOptional -> NavType.StringType // null boolean is not supported in androidx.navigation |
|
} |
|
|
|
val isOptional |
|
get() = when (this) { |
|
BooleanOptional -> true |
|
else -> false |
|
} |
|
} |
|
|
|
// Argument names |
|
enum class NavArgument( |
|
val type: ArgumentType, |
|
) { |
|
ExampleId(type = ArgumentType.Int), |
|
// put all the arguments used in you app here |
|
} |
|
|
|
// The actual argument used in navigation |
|
data class DestArgument( |
|
val argument: NavArgument, |
|
val isNullable: Boolean = false, |
|
val defaultValue: Any? = null, |
|
) { |
|
// Converts to androidx.navigation argument |
|
fun toNamedNavArgument() = navArgument(argument.name) { |
|
type = argument.type.toNavType() |
|
nullable = isNullable || argument.type.isOptional |
|
if (this@DestArgument.defaultValue != null) { |
|
defaultValue = this@DestArgument.defaultValue |
|
} |
|
} |
|
|
|
companion object { |
|
fun NavBackStackEntry.getStringArg(destArgument: DestArgument?) = |
|
if (destArgument?.argument?.type == ArgumentType.String) |
|
arguments?.getString( |
|
destArgument.argument.name, |
|
destArgument.defaultValue as? String? |
|
) |
|
else null |
|
|
|
fun NavBackStackEntry.getIntArg(destArgument: DestArgument?) = |
|
if (destArgument?.argument?.type == ArgumentType.Int) |
|
if (destArgument.defaultValue is Int) |
|
arguments?.getInt(destArgument.argument.name, destArgument.defaultValue) |
|
else arguments?.getInt(destArgument.argument.name) |
|
else null |
|
|
|
fun NavBackStackEntry.getBoolean(destArgument: DestArgument?) = |
|
if (destArgument?.argument?.type == ArgumentType.Boolean) { |
|
if (destArgument.defaultValue is Boolean) |
|
arguments?.getBoolean(destArgument.argument.name, destArgument.defaultValue) |
|
else arguments?.getBoolean(destArgument.argument.name) |
|
} else if (destArgument?.argument?.type == ArgumentType.BooleanOptional) { |
|
if (destArgument.defaultValue is Boolean) { |
|
arguments?.getString( |
|
destArgument.argument.name, |
|
destArgument.defaultValue.toString() |
|
)?.toBooleanStrictOrNull() |
|
} else arguments?.getString(destArgument.argument.name)?.toBooleanStrictOrNull() |
|
} else null |
|
} |
|
} |
|
|
|
// Put all the destinations here |
|
enum class NavDestination( |
|
private val arguments: List<DestArgument> = emptyList() |
|
) { |
|
ExampleDestination( |
|
arguments = listOf( |
|
DestArgument( |
|
argument = NavArgument.ExampleId |
|
) |
|
) |
|
), |
|
; |
|
|
|
fun findDestArgument(argument: NavArgument) = arguments.find { it.argument == argument } |
|
|
|
fun route() = if (arguments.isEmpty()) name else { |
|
name + arguments |
|
.sortedBy { it.isNullable } |
|
.joinToString(separator = "") { arg -> |
|
if (arg.isNullable) "?${arg.argument.name}={${arg.argument.name}}" |
|
else "/{${arg.argument.name}}" |
|
} |
|
} |
|
|
|
val namedNavArguments get() = arguments.map { it.toNamedNavArgument() } |
|
|
|
fun putArguments(arguments: Map<NavArgument, String?>): String { |
|
var routeWithArguments = route() |
|
arguments.forEach { (arg, value) -> |
|
if (value != null) |
|
routeWithArguments = routeWithArguments.replace("{${arg.name}}", value) |
|
} |
|
return routeWithArguments |
|
} |
|
} |
Usage