Skip to content

Instantly share code, notes, and snippets.

@vganin
Last active March 4, 2017 17:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vganin/cf36838e15d0576fb66a278f88a86f87 to your computer and use it in GitHub Desktop.
Save vganin/cf36838e15d0576fb66a278f88a86f87 to your computer and use it in GitHub Desktop.
Kotlin FragmentArgs
import android.app.Fragment
import android.os.Bundle
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import android.support.v4.app.Fragment as SupportFragment
inline fun <reified T> Fragment.fragmentArg()
: ReadWriteProperty<Fragment, T> = required({ argumentsRequired })
inline fun <reified T> SupportFragment.fragmentArg()
: ReadWriteProperty<SupportFragment, T> = required({ argumentsRequired })
inline fun <reified T> Fragment.fragmentArgOptional()
: ReadWriteProperty<Fragment, T?> = optional({ argumentsRequired })
inline fun <reified T> SupportFragment.fragmentArgOptional()
: ReadWriteProperty<SupportFragment, T?> = optional({ argumentsRequired })
val Fragment.argumentsRequired: Bundle
get() {
if (arguments == null) arguments = Bundle()
return arguments
}
val SupportFragment.argumentsRequired: Bundle
get() {
if (arguments == null) arguments = Bundle()
return arguments
}
inline fun <reified T> Bundle.putArg(key: String, value: T): Unit {
when (value) {
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is String -> getString(key, value)
// TODO: More
else -> throw IllegalStateException("Cannot put type ${T::class.java.name} into Bundle")
}
}
inline fun <reified T> Bundle.getArg(key: String): T? {
return when (T::class) {
Int::class -> getInt(key) as T?
Long::class -> getLong(key) as T?
String::class -> getString(key) as T?
// TODO: More
else -> throw IllegalStateException("Cannot get type ${T::class.java.name} from Bundle")
}
}
inline fun <reified T> required(crossinline bundleSupplier: () -> Bundle) = ReadWriteFragmentArg(
{ prop, value: T -> bundleSupplier().putArg(prop.name, value) },
{ prop -> bundleSupplier().getArg<T>(prop.name) ?: requiredFailed(prop) }
)
inline fun <reified T> optional(crossinline bundleSupplier: () -> Bundle) = ReadWriteFragmentArg(
{ prop, value: T? -> bundleSupplier().putArg(prop.name, value) },
{ prop -> bundleSupplier().getArg<T?>(prop.name) }
)
fun requiredFailed(desc: KProperty<*>): Nothing =
throw IllegalStateException("Required argument for property '${desc.name}' not found")
class ReadWriteFragmentArg<T> (
private val argSetter: (KProperty<*>, T) -> Unit,
private val argGetter: (KProperty<*>) -> T
) : ReadWriteProperty<Any, T> {
private object EMPTY
private var _value: Any? = EMPTY
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
argSetter(property, value)
}
override fun getValue(thisRef: Any, property: KProperty<*>): T {
if (_value == EMPTY) {
_value = argGetter(property)
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment