Created
July 7, 2017 07:11
-
-
Save talenguyen/4c895576bf510d6c3ea0d16356871f74 to your computer and use it in GitHub Desktop.
Bundle binding inspired by KotterKnife
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
import android.app.Activity | |
import android.app.Fragment | |
import android.content.Context | |
import android.content.Intent | |
import android.os.Bundle | |
import android.os.Parcelable | |
import android.support.annotation.VisibleForTesting | |
import android.support.v4.app.FragmentActivity | |
import android.util.SparseArray | |
import java.util.* | |
import kotlin.properties.ReadOnlyProperty | |
import kotlin.reflect.KProperty | |
import android.support.v4.app.Fragment as SupportFragment | |
/** | |
* Created by Giang Nguyen on 7/5/17. | |
*/ | |
inline fun <reified T : Activity> Context.intentOf(vararg extras: Pair<String, Any>): Intent { | |
val intent = Intent(this, T::class.java) | |
if (extras.isNotEmpty()) { | |
val bundle = bundle(*extras) | |
intent.putExtras(bundle) | |
} | |
return intent | |
} | |
fun bundle(vararg extras: Pair<String, Any>): Bundle { | |
val bundle = Bundle() | |
for ((key, value) in extras) { | |
bundle.put(key, value) | |
} | |
return bundle | |
} | |
@VisibleForTesting internal fun Bundle.put(key: String, value: Any) { | |
when (value) { | |
is Boolean -> putBoolean(key, value) | |
is BooleanArray -> putBooleanArray(key, value) | |
is Int -> putInt(key, value) | |
is IntArray -> putIntArray(key, value) | |
is Long -> putLong(key, value) | |
is LongArray -> putLongArray(key, value) | |
is Float -> putFloat(key, value) | |
is FloatArray -> putFloatArray(key, value) | |
is Double -> putDouble(key, value) | |
is DoubleArray -> putDoubleArray(key, value) | |
is String -> putString(key, value) | |
is CharSequence -> putCharSequence(key, value) | |
is Parcelable -> putParcelable(key, value) | |
is Array<*> -> putArray(key, value) | |
is ArrayList<*> -> putArrayList(key, value) | |
is SparseArray<*> -> @Suppress("UNCHECKED_CAST") putSparseParcelableArray( | |
key, | |
value as SparseArray<out Parcelable>?) | |
else -> notSupportForType(value) | |
} | |
} | |
private fun notSupportForType(value: Any) { | |
throw IllegalArgumentException("not support for ${value::class}") | |
} | |
fun Bundle.putArrayList(key: String, value: ArrayList<*>) { | |
if (value.isEmpty()) { | |
return | |
} | |
@Suppress("UNCHECKED_CAST") | |
when (value[0]) { | |
is Int -> putIntegerArrayList(key, value as ArrayList<Int>?) | |
is String -> putStringArrayList(key, value as ArrayList<String>?) | |
is CharSequence -> putCharSequenceArrayList(key, value as ArrayList<CharSequence>?) | |
is Parcelable -> putParcelableArrayList(key, value as ArrayList<Parcelable>?) | |
else -> notSupportForType(value) | |
} | |
} | |
private fun Bundle.putArray(key: String, value: Array<*>) { | |
if (value.isEmpty()) { | |
return | |
} | |
@Suppress("UNCHECKED_CAST") | |
when (value[0]) { | |
is String -> putStringArray(key, value as Array<out String>?) | |
is CharSequence -> putCharSequenceArray(key, value as Array<out String>?) | |
is Parcelable -> putParcelableArray(key, value as Array<out Parcelable>?) | |
} | |
} | |
fun <V> Activity.extra(key: String): | |
ReadOnlyProperty<Activity, V> = required(key, extraFinder) | |
fun <V> FragmentActivity.extra(key: String): | |
ReadOnlyProperty<FragmentActivity, V> = required(key, extraFinder) | |
fun <V> Fragment.arg(key: String): | |
ReadOnlyProperty<Fragment, V> = required(key, extraFinder) | |
fun <V> SupportFragment.arg(key: String): | |
ReadOnlyProperty<Fragment, V> = required(key, extraFinder) | |
private val Activity.extraFinder: Activity.(String) -> Any? | |
get() = { intent.extras.get(it) } | |
private val Fragment.extraFinder: Fragment.(String) -> Any? | |
get() = { arguments.get(it) } | |
private val SupportFragment.extraFinder: Fragment.(String) -> Any? | |
get() = { arguments.get(it) } | |
private fun keyNotFound(key: String, desc: KProperty<*>): Nothing = | |
throw IllegalStateException("Key $key for '${desc.name}' not found.") | |
@Suppress("UNCHECKED_CAST") | |
private fun <T, V> required(id: String, finder: T.(String) -> Any?) | |
= Lazy { t: T, desc -> t.finder(id) as V? ?: keyNotFound(id, desc) } | |
// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it | |
private class Lazy<in T, out V>( | |
private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty<T, V> { | |
private object EMPTY | |
private var value: Any? = EMPTY | |
override fun getValue(thisRef: T, property: KProperty<*>): V { | |
if (value == EMPTY) { | |
value = initializer(thisRef, property) | |
} | |
@Suppress("UNCHECKED_CAST") | |
return value as V | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment