Skip to content

Commit 6d58a63

Browse files
Merge pull request #2 from Omega-R/develop
Add bindable delegates
2 parents efe61dd + 13dd358 commit 6d58a63

File tree

10 files changed

+301
-10
lines changed

10 files changed

+301
-10
lines changed

app/src/main/java/com/omega_r/bind/app/MainActivity.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import android.util.SparseArray
66
import android.view.View
77
import android.view.ViewGroup
88
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
9-
import com.omega_r.bind.OmegaAutoAdapter
10-
import com.omega_r.bind.OmegaBindView
9+
import com.omega_r.bind.adapters.OmegaAutoAdapter
10+
import com.omega_r.bind.views.OmegaBindView
1111
import com.omega_r.bind.model.BindModel
1212
import com.omega_r.bind.model.binders.*
1313

@@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
1818
bindVisible(R.id.NO_DEBUG) {
1919
true
2020
}
21-
bindMultiCustom(R.id.NO_DEBUG, R.id.NO_DEBUG) { sparseArray: SparseArray<View>, s: String ->
21+
bindMultiCustom(R.id.NO_DEBUG, R.id.NO_DEBUG) { sparseArray: SparseArray<View>, s ->
2222
sparseArray[R.id.NO_DEBUG]
2323
}
2424
}

library/src/main/java/com/omega_r/bind/OmegaAutoAdapter.kt renamed to library/src/main/java/com/omega_r/bind/adapters/OmegaAutoAdapter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
package com.omega_r.bind
1+
package com.omega_r.bind.adapters
22

33
import android.view.ViewGroup
44
import androidx.annotation.LayoutRes
55
import com.omega_r.adapters.OmegaAdapter
66
import com.omega_r.adapters.OmegaIdentifiable
77
import com.omega_r.adapters.OmegaListAdapter
8+
import com.omega_r.bind.R
89
import com.omega_r.bind.model.BindModel
910
import com.omega_r.libs.omegarecyclerview.OmegaRecyclerView
1011
import kotlin.reflect.KClass

library/src/main/java/com/omega_r/bind/OmegaStickyAutoAdapter.kt renamed to library/src/main/java/com/omega_r/bind/adapters/OmegaStickyAutoAdapter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.omega_r.bind
1+
package com.omega_r.bind.adapters
22

33
import android.view.ViewGroup
44
import androidx.annotation.LayoutRes
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.omega_r.bind.delegates
2+
3+
/**
4+
* Created by Anton Knyazev on 10.04.2019.
5+
*/
6+
interface IdHolder {
7+
val id: Int
8+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.omega_r.bind.delegates
2+
3+
import android.animation.AnimatorInflater
4+
import android.content.res.Resources
5+
import android.view.View
6+
import android.view.animation.AnimationUtils
7+
import androidx.annotation.*
8+
import androidx.core.content.ContextCompat
9+
import androidx.recyclerview.widget.RecyclerView
10+
import com.omega_r.bind.delegates.managers.BindersManager
11+
import com.omega_r.bind.delegates.managers.BindersManager.BindType.RESETTABLE
12+
import com.omega_r.bind.delegates.managers.BindersManager.BindType.RESETTABLE_WITH_AUTO_INIT
13+
import com.omega_r.bind.adapters.OmegaAutoAdapter
14+
import com.omega_r.bind.model.BindModel
15+
import com.omega_r.click.OmegaContextable
16+
import com.omega_r.click.OmegaViewFindable
17+
18+
/**
19+
* Created by Anton Knyazev on 04.04.2019.
20+
*/
21+
@Suppress("unused")
22+
interface OmegaBindable : OmegaContextable, OmegaViewFindable {
23+
24+
25+
private val resources: Resources
26+
get() = getContext()?.resources ?: error("Context is null")
27+
28+
val bindersManager: BindersManager
29+
30+
private fun <T : View> findView(id: Int): T {
31+
return findViewById(id)
32+
?: error("Bind is not found R.id.${this.getContext()!!.resources.getResourceEntryName(id)} (${this::class.java.name})")
33+
}
34+
35+
private fun <T : View> findViewOrNull(id: Int): T? {
36+
return findViewById(id)
37+
}
38+
39+
private fun <T : View> findViews(vararg ids: Int): List<T> {
40+
return ids.map { findView(it) }
41+
}
42+
43+
private fun <T : View> findViewsToMap(vararg ids: Int): Map<Int, T> {
44+
return ids.associate { it to findView(it) }
45+
}
46+
47+
private fun <T : View, IH : IdHolder> findViewsToIdHolderMap(ids: Array<out IH>): Map<IH, T> {
48+
return ids.associate { it to findView(it.id) }
49+
}
50+
51+
private fun <T : View, E> findViewsToIdPairMap(ids: Array<out Pair<E, Int>>): Map<E, T> {
52+
return ids.associate { it.first to findView(it.second) }
53+
}
54+
55+
fun <T : RecyclerView> bind(@IdRes res: Int, adapter: RecyclerView.Adapter<*>) =
56+
bindersManager.bind<T>(RESETTABLE_WITH_AUTO_INIT, { findView(res) }) {
57+
this.adapter = adapter
58+
}
59+
60+
fun <T : RecyclerView, M> bind(
61+
@IdRes res: Int,
62+
@LayoutRes layoutRes: Int,
63+
parentModel: BindModel<M>? = null,
64+
callback: ((M) -> Unit)? = null,
65+
builder: BindModel.Builder<M>.() -> Unit
66+
) =
67+
bindersManager.bind<T>(RESETTABLE_WITH_AUTO_INIT, { findView(res) }) {
68+
adapter =
69+
OmegaAutoAdapter.create(layoutRes, callback, parentModel = parentModel, block = builder)
70+
}
71+
72+
fun <T : RecyclerView> bind(@IdRes res: Int, adapter: RecyclerView.Adapter<*>, initBlock: T.() -> Unit) =
73+
bindersManager.bind<T>(RESETTABLE_WITH_AUTO_INIT, { findView(res) }) {
74+
this.adapter = adapter
75+
initBlock()
76+
}
77+
78+
fun <T : View> bind(@IdRes res: Int, initBlock: T.() -> Unit) =
79+
bindersManager.bind(RESETTABLE_WITH_AUTO_INIT, { findView(res) }, initBlock)
80+
81+
fun <T : View> bind(@IdRes res: Int) = bindersManager.bind<T>(RESETTABLE_WITH_AUTO_INIT, { findView(res) })
82+
83+
fun <T> bind(init: () -> T) = bindersManager.bind(RESETTABLE, init)
84+
85+
fun <T : View> bind(@IdRes vararg ids: Int): Lazy<List<T>> {
86+
return bindersManager.bind(RESETTABLE, { findViews(*ids) })
87+
}
88+
89+
fun <T : View> bind(@IdRes vararg ids: Int, initBlock: T.() -> Unit): Lazy<List<T>> =
90+
bindersManager.bind(RESETTABLE_WITH_AUTO_INIT, { findViews(*ids) }) {
91+
forEach(initBlock)
92+
}
93+
94+
fun <T : View, IH : IdHolder> bind(ids: Array<out IH>): Lazy<Map<IH, T>> =
95+
bindersManager.bind(RESETTABLE, { findViewsToIdHolderMap(ids) })
96+
97+
fun <T : View, IH : IdHolder> bind(ids: Array<out IH>, initBlock: T.(IdHolder) -> Unit): Lazy<Map<IH, T>> =
98+
bindersManager.bind(RESETTABLE_WITH_AUTO_INIT, { findViewsToIdHolderMap(ids) }) {
99+
forEach {
100+
initBlock(it.value, it.key)
101+
}
102+
}
103+
104+
fun <T : View, E> bind(vararg idsPair: Pair<E, Int>) =
105+
bindersManager.bind(RESETTABLE, { findViewsToIdPairMap<T, E>(idsPair) })
106+
107+
fun <T : View, E> bind(vararg idsPair: Pair<E, Int>, initBlock: T.(E) -> Unit) =
108+
bindersManager.bind(RESETTABLE_WITH_AUTO_INIT, { findViewsToIdPairMap<T, E>(idsPair) }) {
109+
forEach { initBlock(it.value, it.key) }
110+
}
111+
112+
fun <T : View> bindOrNull(@IdRes res: Int) = bindersManager.bind(RESETTABLE, { findViewOrNull<T>(res) })
113+
114+
fun <T : View> bindOrNull(@IdRes res: Int, initBlock: T.() -> Unit) =
115+
bindersManager.bind(RESETTABLE_WITH_AUTO_INIT, { findViewOrNull<T>(res) }) {
116+
this?.let(initBlock)
117+
}
118+
119+
fun bindColor(@ColorRes res: Int) = bindersManager.bind(findInit = {
120+
ContextCompat.getColor(getContext()!!, res)
121+
})
122+
123+
fun bindInt(@IntegerRes res: Int) = bindersManager.bind(findInit = {
124+
resources.getInteger(res)
125+
})
126+
127+
fun bindDrawable(@DrawableRes res: Int) = bindersManager.bind(findInit = {
128+
ContextCompat.getDrawable(getContext()!!, res)
129+
?: error("BindDrawable is not found R.drawable.${resources.getResourceEntryName(res)} (${this::class.java.name})")
130+
})
131+
132+
fun bindDimen(@DimenRes res: Int) = bindersManager.bind(findInit = {
133+
resources.getDimension(res)
134+
})
135+
136+
fun bindDimenPixel(@DimenRes res: Int) = bindersManager.bind(findInit = {
137+
resources.getDimensionPixelSize(res)
138+
})
139+
140+
fun bindAnimation(@AnimRes res: Int) = bindersManager.bind(findInit = {
141+
AnimationUtils.loadAnimation(getContext(), res)
142+
})
143+
144+
fun bindAnimator(@AnimatorRes res: Int) = bindersManager.bind(findInit = {
145+
AnimatorInflater.loadAnimator(getContext(), res)
146+
})
147+
148+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.omega_r.bind.delegates.managers
2+
3+
/**
4+
* Created by Anton Knyazev on 04.04.2019.
5+
*/
6+
@Suppress("unused")
7+
open class BindersManager {
8+
9+
private val autoInitList = mutableListOf<Lazy<*>>()
10+
11+
fun <V> bind(bindType: BindType = BindType.STATIC, findInit: () -> V, objectInit: (V.() -> Unit)? = null): Lazy<V> {
12+
val lazy = createLazy(bindType, findInit, objectInit)
13+
if (bindType == BindType.RESETTABLE_WITH_AUTO_INIT) {
14+
autoInitList += lazy
15+
}
16+
return lazy
17+
}
18+
19+
protected open fun <V> createLazy(
20+
bindType: BindType = BindType.STATIC,
21+
findInit: () -> V,
22+
objectInit: (V.() -> Unit)? = null
23+
): Lazy<V> = BindLazy(findInit, objectInit)
24+
25+
fun doAutoInit() {
26+
autoInitList.forEach { it.value }
27+
}
28+
29+
enum class BindType {
30+
STATIC, RESETTABLE, RESETTABLE_WITH_AUTO_INIT
31+
}
32+
33+
open class BindLazy<T>(initializer: () -> T, objectInitializer: (T.() -> Unit)?) : Lazy<T> {
34+
protected var initializer: (() -> T)? = initializer
35+
36+
@Suppress("CanBePrimaryConstructorProperty")
37+
protected var objectInitializer: (T.() -> Unit)? = objectInitializer
38+
39+
protected var realValue: Any? = UNINITIALIZED_VALUE
40+
41+
override val value: T
42+
get() {
43+
if (realValue === UNINITIALIZED_VALUE) {
44+
initializer!!().also { value ->
45+
realValue = value
46+
initializer = null
47+
objectInitializer?.let {
48+
objectInitializer!!(value)
49+
objectInitializer = null
50+
}
51+
}
52+
}
53+
@Suppress("UNCHECKED_CAST")
54+
return realValue as T
55+
}
56+
57+
override fun isInitialized(): Boolean = realValue !== UNINITIALIZED_VALUE
58+
59+
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
60+
61+
private fun writeReplace(): Any = InitializedLazyImpl(value)
62+
63+
@Suppress("ClassName")
64+
protected object UNINITIALIZED_VALUE
65+
}
66+
67+
internal class InitializedLazyImpl<out T>(override val value: T) : Lazy<T> {
68+
69+
override fun isInitialized(): Boolean = true
70+
71+
override fun toString(): String = value.toString()
72+
73+
}
74+
75+
76+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.omega_r.bind.delegates.managers
2+
3+
import java.util.*
4+
5+
/**
6+
* Created by Anton Knyazev on 04.04.2019.
7+
*/
8+
@Suppress("unused")
9+
class ResettableBindersManager : BindersManager() {
10+
11+
// we synchronize to make sure the timing of a reset() call and new init do not collide
12+
private val managedDelegates = LinkedList<ResettableLazy<*>>()
13+
14+
private fun ResettableLazy<*>.registerInitiatedLazy() {
15+
synchronized(managedDelegates) {
16+
managedDelegates.add(this)
17+
}
18+
}
19+
20+
override fun <V> createLazy(bindType: BindType, findInit: () -> V, objectInit: (V.() -> Unit)?): Lazy<V> {
21+
return when (bindType) {
22+
BindType.RESETTABLE, BindType.RESETTABLE_WITH_AUTO_INIT -> ResettableLazy(findInit, objectInit)
23+
else -> super.createLazy(bindType, findInit, objectInit)
24+
}
25+
}
26+
27+
fun reset() {
28+
synchronized(managedDelegates) {
29+
if (managedDelegates.isNotEmpty()) {
30+
managedDelegates.forEach { it.reset() }
31+
managedDelegates.clear()
32+
}
33+
}
34+
}
35+
36+
inner class ResettableLazy<V>(findObject: () -> V, objectInit: (V.() -> Unit)? = null) :
37+
BindLazy<V>(findObject, objectInit) {
38+
39+
override val value: V
40+
get() {
41+
if (realValue === UNINITIALIZED_VALUE) {
42+
registerInitiatedLazy()
43+
initializer!!().also { value ->
44+
realValue = value
45+
objectInitializer?.let {
46+
objectInitializer!!(value)
47+
}
48+
}
49+
}
50+
@Suppress("UNCHECKED_CAST")
51+
return realValue as V
52+
}
53+
54+
55+
internal fun reset() {
56+
realValue = UNINITIALIZED_VALUE
57+
}
58+
59+
}
60+
61+
}

library/src/main/java/com/omega_r/bind/model/BindModel.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ package com.omega_r.bind.model
33
import android.app.Activity
44
import android.util.SparseArray
55
import android.view.View
6-
import android.view.ViewGroup
7-
import android.widget.FrameLayout
8-
import androidx.annotation.LayoutRes
96
import com.omega_r.bind.R
107
import com.omega_r.bind.model.binders.*
118

library/src/main/java/com/omega_r/bind/model/binders/RecyclerViewListBinder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.omega_r.bind.model.binders
22

33
import androidx.annotation.IdRes
44
import androidx.recyclerview.widget.RecyclerView
5-
import com.omega_r.bind.OmegaAutoAdapter
5+
import com.omega_r.bind.adapters.OmegaAutoAdapter
66
import com.omega_r.bind.model.BindModel
77
import com.omega_r.libs.omegarecyclerview.OmegaRecyclerView
88
import kotlin.reflect.KProperty

library/src/main/java/com/omega_r/bind/OmegaBindView.kt renamed to library/src/main/java/com/omega_r/bind/views/OmegaBindView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.omega_r.bind
1+
package com.omega_r.bind.views
22

33
import android.content.Context
44
import android.util.AttributeSet

0 commit comments

Comments
 (0)