package com.pitchedapps.frost.utils /** * Created by Allan Wang on 2017-05-29. * * Courtesy of Jake Wharton * * https://github.com/JakeWharton/kotterknife/blob/master/src/main/kotlin/kotterknife/ButterKnife.kt */ import android.app.Activity import android.app.Dialog import android.app.DialogFragment import android.app.Fragment import android.support.v7.widget.RecyclerView.ViewHolder import android.view.View import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty import android.support.v4.app.DialogFragment as SupportDialogFragment import android.support.v4.app.Fragment as SupportFragment public fun View.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun Activity.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun Dialog.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun DialogFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun SupportDialogFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun Fragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun SupportFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun ViewHolder.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) public fun View.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun Activity.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun Dialog.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun DialogFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun SupportDialogFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun Fragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun SupportFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun ViewHolder.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) public fun View.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun Activity.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun Dialog.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun DialogFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun SupportDialogFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun Fragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun SupportFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun ViewHolder.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) public fun View.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun Activity.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun Dialog.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun DialogFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun SupportDialogFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun Fragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun SupportFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) public fun ViewHolder.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) private val View.viewFinder: View.(Int) -> View? get() = { findViewById(it) } private val Activity.viewFinder: Activity.(Int) -> View? get() = { findViewById(it) } private val Dialog.viewFinder: Dialog.(Int) -> View? get() = { findViewById(it) } private val DialogFragment.viewFinder: DialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } private val SupportDialogFragment.viewFinder: SupportDialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } private val Fragment.viewFinder: Fragment.(Int) -> View? get() = { view.findViewById(it) } private val SupportFragment.viewFinder: SupportFragment.(Int) -> View? get() = { view!!.findViewById(it) } private val ViewHolder.viewFinder: ViewHolder.(Int) -> View? get() = { itemView.findViewById(it) } private fun viewNotFound(id:Int, desc: KProperty<*>): Nothing = throw IllegalStateException("View ID $id for '${desc.name}' not found.") @Suppress("UNCHECKED_CAST") private fun required(id: Int, finder: T.(Int) -> View?) = Lazy { t: T, desc -> t.finder(id) as V? ?: viewNotFound(id, desc) } @Suppress("UNCHECKED_CAST") private fun optional(id: Int, finder: T.(Int) -> View?) = Lazy { t: T, desc -> t.finder(id) as V? } @Suppress("UNCHECKED_CAST") private fun required(ids: IntArray, finder: T.(Int) -> View?) = Lazy { t: T, desc -> ids.map { t.finder(it) as V? ?: viewNotFound(it, desc) } } @Suppress("UNCHECKED_CAST") private fun optional(ids: IntArray, finder: T.(Int) -> View?) = Lazy { t: T, desc -> ids.map { t.finder(it) as V? }.filterNotNull() } // Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it private class Lazy(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty { 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 } }