From 48213d0b427c478865c75fee912ff1ae8bbaffb5 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 31 Jul 2017 23:02:01 -0700 Subject: Major update to core and kotterknife; create mediapicker (#15) * Readme * Fix kau direction bits * Truly support transparent ripples * Update changelog * Test rect as base * Replace fab transition with generic fade scale transition * Add scalexy func * Add scaleXY * Add arguments to fadeScaleTransition * Clean up ink indicator * Create setOnSingleTapListener * Fix lint and add rndColor * Create kotterknife resettables * Add readme and missing object * Create lazy resettable registered * Update core docs * Opt for separate class for resettable registry * Clean up resettable registry * Rename functions * Add ripple callback listener * Adjust kprefactivity desc color * Add more transitions * Add delete keys option * Add instrumentation tests * switch id * Revert automatic instrumental tests * Generify imagepickercore and prepare video alternative * Create working video picker * Address possible null issue * Update searchview * Make layouts public * Add changelog test * Update logo link * Add custom color gif --- .../kotlin/ca/allanwang/kau/utils/Kotterknife.kt | 183 ++++++++++++++++++--- 1 file changed, 163 insertions(+), 20 deletions(-) (limited to 'core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt') diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt index 3783931..f3c08bd 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt @@ -1,3 +1,5 @@ +@file:Suppress("UNCHECKED_CAST") + package ca.allanwang.kau.utils /** @@ -13,6 +15,7 @@ import android.app.DialogFragment import android.app.Fragment import android.support.v7.widget.RecyclerView.ViewHolder import android.view.View +import java.util.* import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty import android.support.v4.app.DialogFragment as SupportDialogFragment @@ -30,13 +33,13 @@ fun Dialog.bindView(id: Int) fun DialogFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) -fun android.support.v4.app.DialogFragment.bindView(id: Int) +fun SupportDialogFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) fun Fragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) -fun android.support.v4.app.Fragment.bindView(id: Int) +fun SupportFragment.bindView(id: Int) : ReadOnlyProperty = required(id, viewFinder) fun ViewHolder.bindView(id: Int) @@ -54,13 +57,13 @@ fun Dialog.bindOptionalView(id: Int) fun DialogFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) -fun android.support.v4.app.DialogFragment.bindOptionalView(id: Int) +fun SupportDialogFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) fun Fragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) -fun android.support.v4.app.Fragment.bindOptionalView(id: Int) +fun SupportFragment.bindOptionalView(id: Int) : ReadOnlyProperty = optional(id, viewFinder) fun ViewHolder.bindOptionalView(id: Int) @@ -78,13 +81,13 @@ fun Dialog.bindViews(vararg ids: Int) fun DialogFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) -fun android.support.v4.app.DialogFragment.bindViews(vararg ids: Int) +fun SupportDialogFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) fun Fragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) -fun android.support.v4.app.Fragment.bindViews(vararg ids: Int) +fun SupportFragment.bindViews(vararg ids: Int) : ReadOnlyProperty> = required(ids, viewFinder) fun ViewHolder.bindViews(vararg ids: Int) @@ -102,13 +105,13 @@ fun Dialog.bindOptionalViews(vararg ids: Int) fun DialogFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) -fun android.support.v4.app.DialogFragment.bindOptionalViews(vararg ids: Int) +fun SupportDialogFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) fun Fragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) -fun android.support.v4.app.Fragment.bindOptionalViews(vararg ids: Int) +fun SupportFragment.bindOptionalViews(vararg ids: Int) : ReadOnlyProperty> = optional(ids, viewFinder) fun ViewHolder.bindOptionalViews(vararg ids: Int) @@ -122,11 +125,11 @@ private inline val Dialog.viewFinder: Dialog.(Int) -> View? get() = { findViewById(it) } private inline val DialogFragment.viewFinder: DialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } -private inline val android.support.v4.app.DialogFragment.viewFinder: android.support.v4.app.DialogFragment.(Int) -> View? +private inline val SupportDialogFragment.viewFinder: SupportDialogFragment.(Int) -> View? get() = { dialog.findViewById(it) } private inline val Fragment.viewFinder: Fragment.(Int) -> View? get() = { view.findViewById(it) } -private inline val android.support.v4.app.Fragment.viewFinder: android.support.v4.app.Fragment.(Int) -> View? +private inline val SupportFragment.viewFinder: SupportFragment.(Int) -> View? get() = { view!!.findViewById(it) } private inline val ViewHolder.viewFinder: ViewHolder.(Int) -> View? get() = { itemView.findViewById(it) } @@ -134,33 +137,173 @@ private inline val ViewHolder.viewFinder: ViewHolder.(Int) -> View? 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?)?.apply { } ?: viewNotFound(id, desc) } -@Suppress("UNCHECKED_CAST") private fun optional(id: Int, finder: T.(Int) -> View?) = Lazy { t: T, _ -> 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, _ -> 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 open class Lazy(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty { + protected object EMPTY - private var value: Any? = EMPTY + protected var value: Any? = EMPTY override fun getValue(thisRef: T, property: KProperty<*>): V { - if (value == EMPTY) { + if (value == EMPTY) value = initializer(thisRef, property) - } - @Suppress("UNCHECKED_CAST") + return value as V } +} + +/* + * The components below are a variant of the view bindings with lazy resettables + * All bindings are weakly held so that they may be reset through KotterknifeRegistry.reset + * + * This is typically only needed in cases such as Fragments, + * where their lifecycle doesn't match that of an Activity or View + * + * Credits to MichaelRocks + */ + +fun View.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun Activity.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun Dialog.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun DialogFragment.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun SupportDialogFragment.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun Fragment.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun SupportFragment.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun ViewHolder.bindViewResettable(id: Int) + : ReadOnlyProperty = requiredResettable(id, viewFinder) + +fun View.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun Activity.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun Dialog.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun DialogFragment.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun SupportDialogFragment.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun Fragment.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun SupportFragment.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun ViewHolder.bindOptionalViewResettable(id: Int) + : ReadOnlyProperty = optionalResettable(id, viewFinder) + +fun View.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun Activity.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun Dialog.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun DialogFragment.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun SupportDialogFragment.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun Fragment.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun SupportFragment.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun ViewHolder.bindViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = requiredResettable(ids, viewFinder) + +fun View.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun Activity.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun Dialog.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun DialogFragment.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun SupportDialogFragment.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun Fragment.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun SupportFragment.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +fun ViewHolder.bindOptionalViewsResettable(vararg ids: Int) + : ReadOnlyProperty> = optionalResettable(ids, viewFinder) + +private fun requiredResettable(id: Int, finder: T.(Int) -> View?) + = LazyResettable { t: T, desc -> (t.finder(id) as V?)?.apply { } ?: viewNotFound(id, desc) } + +private fun optionalResettable(id: Int, finder: T.(Int) -> View?) + = LazyResettable { t: T, _ -> t.finder(id) as V? } + +private fun requiredResettable(ids: IntArray, finder: T.(Int) -> View?) + = LazyResettable { t: T, desc -> ids.map { t.finder(it) as V? ?: viewNotFound(it, desc) } } + +private fun optionalResettable(ids: IntArray, finder: T.(Int) -> View?) + = LazyResettable { t: T, _ -> ids.map { t.finder(it) as V? }.filterNotNull() } + +//Like Kotterknife's lazy delegate but is resettable +private class LazyResettable(initializer: (T, KProperty<*>) -> V) : Lazy(initializer) { + override fun getValue(thisRef: T, property: KProperty<*>): V { + KotterknifeRegistry.register(thisRef!!, this) + return super.getValue(thisRef, property) + } + + fun reset() { + value = EMPTY + } +} + +object Kotterknife { + fun reset(target: Any) { + KotterknifeRegistry.reset(target) + } +} + +private object KotterknifeRegistry { + private val lazyMap = WeakHashMap>>() + + fun register(target: Any, lazy: LazyResettable<*, *>) + = lazyMap.getOrPut(target, { Collections.newSetFromMap(WeakHashMap()) }).add(lazy) + + fun reset(target: Any) = lazyMap[target]?.forEach { it.reset() } } \ No newline at end of file -- cgit v1.2.3