iamthevoid
05/20/2023, 8:17 AMiamthevoid
05/20/2023, 8:17 AMinterface Navigator {
companion object {
const val PARAMS_SEPARATOR = "&"
const val PARAMS_START_SEPARATOR = "?"
const val PARAMS_KV_SEPARATOR = "="
}
fun <T: Enum<T>> T.addParam(key: String, value: Any) : String {
return name.addParam(key, "$value")
}
fun String.addParam(key: String, value: String) : String {
return buildString {
append(this@addParam)
append(if (contains(PARAMS_START_SEPARATOR)) PARAMS_SEPARATOR else PARAMS_START_SEPARATOR)
append("$key$PARAMS_KV_SEPARATOR$value")
}
}
}
iamthevoid
05/20/2023, 8:18 AMenum class Routes: Navigator {
LIST,
ADD_SOURCE,
SOURCE_SCREEN ,
;
companion object {
const val KEY_SOURCE_ID = "source_id"
}
}
iamthevoid
05/20/2023, 8:19 AMiamthevoid
05/20/2023, 8:19 AMiamthevoid
05/20/2023, 8:20 AMiamthevoid
05/20/2023, 8:21 AMnavController.navigate(Routes.SOURCE_SCREEN.addParam(Routes.KEY_SOURCE_ID, it))
But it is impossible because methods defined in scope of navigator as extensionsiamthevoid
05/20/2023, 8:22 AMiamthevoid
05/20/2023, 8:24 AMinterface Navigator<T: Enum<T>> {
companion object {
const val PARAMS_SEPARATOR = "&"
const val PARAMS_START_SEPARATOR = "?"
const val PARAMS_KV_SEPARATOR = "="
}
fun addParam(key: String, value: Any) : String {
return (this as T).name.addParam(key, "$value")
}
fun String.addParam(key: String, value: String) : String {
return buildString {
append(this@addParam)
append(if (contains(PARAMS_START_SEPARATOR)) PARAMS_SEPARATOR else PARAMS_START_SEPARATOR)
append("$key$PARAMS_KV_SEPARATOR$value")
}
}
}
It worked but it is dirty a bit, and i cant build chains like
Routes.ROUTE.addParam(key,value).addParam(key, value)
Because method for string is not modified yet and can't be modified to looks for user the same, as method for enum do
So it is bad approachiamthevoid
05/20/2023, 8:25 AMiamthevoid
05/20/2023, 8:27 AMenum class Routes: Navigator {
LIST,
ADD_SOURCE,
SOURCE_SCREEN {
fun addSourceId(sourceId: Long) {
this.addParam(KEY_SOURCE_ID, sourceId)
}
},
;
companion object {
const val KEY_SOURCE_ID = "source_id"
}
}
Compiler allow it, and i can build chains, good. But, for some reason compiler doesn't allow to call this method on enum member
navController.navigate(Routes.SOURCE_SCREEN.addSourceId(it))
iamthevoid
05/20/2023, 8:30 AMiamthevoid
05/20/2023, 8:59 AMinterface PathBuilder<T: Enum<T>> {
companion object {
const val PARAMS_SEPARATOR = "&"
const val PARAMS_START_SEPARATOR = "?"
const val PARAMS_KV_SEPARATOR = "="
}
fun addParam(key: String, value: Any) : String
fun addParams(param: Pair<String, Any>, vararg params: Pair<String, Any>) : String
fun String.addParamInternal(key: String, value: Any) : String {
return buildString {
append(this@addParamInternal)
append(if (contains(PARAMS_START_SEPARATOR)) PARAMS_SEPARATOR else PARAMS_START_SEPARATOR)
append("$key${PARAMS_KV_SEPARATOR}$value")
}
}
}
Inheritor
internal class DefaultPathBuilder<T : Enum<T>>(private val item: T) : PathBuilder<T> {
override fun addParam(key: String, value: Any): String {
return item.name.addParamInternal(key, "$value")
}
override fun addParams(param: Pair<String, Any>, vararg params: Pair<String, Any>): String {
var path = item.name.addParamInternal(param.first, "${param.second}")
for ((key, value) in params) {
path = path.addParamInternal(key, value)
}
return path
}
}
Interface
interface Navigator<T : Enum<T>> {
fun pathBuilder(): PathBuilder<T> = DefaultPathBuilder(this as T)
}
Usage
val route = Routes.SOURCE_SCREEN.pathBuilder().addParam(Routes.KEY_SOURCE_ID, it)
navController.navigate(route)
iamthevoid
05/20/2023, 9:00 AM