Skip to content

Commit ba59554

Browse files
author
Alex
committed
Update widgets
1 parent 9ed78a1 commit ba59554

File tree

5 files changed

+104
-62
lines changed

5 files changed

+104
-62
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.alexdeww.reactiveviewmodel.widget
2+
3+
import android.view.View
4+
import androidx.annotation.CallSuper
5+
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
6+
import io.reactivex.rxjava3.core.Observable
7+
import io.reactivex.rxjava3.disposables.CompositeDisposable
8+
import io.reactivex.rxjava3.disposables.Disposable
9+
10+
abstract class BaseVisualControl<T>(
11+
initialValue: T
12+
) : BaseControl() {
13+
14+
val value = state(initialValue)
15+
val isEnabled = state(true)
16+
val isVisible = state(true)
17+
18+
val actionChangeValue = action<T>()
19+
20+
protected open fun transformObservable(observable: Observable<T>): Observable<T> = observable
21+
22+
@CallSuper
23+
protected open fun onChangedValue(newValue: T) {
24+
value.consumer.accept(newValue)
25+
}
26+
27+
init {
28+
actionChangeValue
29+
.observable
30+
.filter { it != value.value }
31+
.let { transformObservable(it) }
32+
.subscribe(::onChangedValue)
33+
}
34+
35+
}
36+
37+
internal fun <T> BaseVisualControl<T>.commonBindTo(
38+
view: View,
39+
invisibleState: Int
40+
): Disposable = CompositeDisposable().apply {
41+
add(
42+
isEnabled
43+
.observable
44+
.observeOn(AndroidSchedulers.mainThread())
45+
.filter { it != view.isEnabled }
46+
.subscribe { view.isEnabled = it }
47+
)
48+
49+
add(
50+
isVisible
51+
.observable
52+
.observeOn(AndroidSchedulers.mainThread())
53+
.filter { it != (view.visibility == View.VISIBLE) }
54+
.subscribe { view.visibility = if (it) View.VISIBLE else invisibleState }
55+
)
56+
}
Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.alexdeww.reactiveviewmodel.widget
22

33
import android.annotation.SuppressLint
4+
import android.view.View
45
import android.widget.CompoundButton
56
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
67
import io.reactivex.rxjava3.core.Observable
@@ -10,36 +11,25 @@ import io.reactivex.rxjava3.disposables.Disposable
1011
@SuppressLint("CheckResult")
1112
class CheckControl internal constructor(
1213
initialChecked: Boolean
13-
) : BaseControl() {
14-
15-
val checked = state(initialChecked)
16-
17-
val actionChange = action<Boolean>()
18-
19-
init {
20-
actionChange
21-
.observable
22-
.filter { it != checked.value }
23-
.subscribe(checked.consumer)
24-
}
25-
26-
}
14+
) : BaseVisualControl<Boolean>(initialChecked)
2715

2816
fun checkControl(initialChecked: Boolean = false): CheckControl = CheckControl(initialChecked)
2917

30-
3118
private val CompoundButton.checkedChanges: Observable<Boolean>
32-
get() = Observable
33-
.create { emitter ->
34-
setOnCheckedChangeListener { _, isChecked -> emitter.onNext(isChecked) }
35-
emitter.setCancellable { setOnCheckedChangeListener(null) }
36-
}
19+
get() = Observable.create { emitter ->
20+
setOnCheckedChangeListener { _, isChecked -> emitter.onNext(isChecked) }
21+
emitter.setCancellable { setOnCheckedChangeListener(null) }
22+
}
3723

38-
fun CheckControl.bindTo(compoundButton: CompoundButton): Disposable {
24+
fun CheckControl.bindTo(
25+
compoundButton: CompoundButton,
26+
invisibleState: Int = View.GONE
27+
): Disposable {
3928
var editing = false
4029
return CompositeDisposable().apply {
30+
add(commonBindTo(compoundButton, invisibleState))
4131
add(
42-
checked
32+
value
4333
.observable
4434
.observeOn(AndroidSchedulers.mainThread())
4535
.subscribe {
@@ -53,7 +43,7 @@ fun CheckControl.bindTo(compoundButton: CompoundButton): Disposable {
5343
compoundButton
5444
.checkedChanges
5545
.filter { !editing }
56-
.subscribe(actionChange.consumer)
46+
.subscribe(actionChangeValue.consumer)
5747
)
5848
}
5949
}

reactiveviewmodel/src/main/java/com/alexdeww/reactiveviewmodel/widget/DialogControl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ class DialogControl<T, R> internal constructor() : BaseControl() {
2020
private val result = action<R>()
2121

2222
val displayed = state<Display>(Display.Absent)
23-
val isShowing
24-
get() = displayed.value is Display.Displayed<*>
23+
val isShowing get() = displayed.value is Display.Displayed<*>
2524

2625
fun show(data: T) {
2726
dismiss()

reactiveviewmodel/src/main/java/com/alexdeww/reactiveviewmodel/widget/InputControl.kt

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.alexdeww.reactiveviewmodel.widget
22

33
import android.annotation.SuppressLint
44
import android.text.*
5+
import android.view.View
56
import android.widget.EditText
67
import com.google.android.material.textfield.TextInputLayout
78
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -14,24 +15,20 @@ typealias FormatterAction = (text: String) -> String
1415
@SuppressLint("CheckResult")
1516
class InputControl internal constructor(
1617
initialText: String,
17-
hideErrorOnUserInput: Boolean,
18-
formatter: FormatterAction?
19-
) : BaseControl() {
18+
private val hideErrorOnUserInput: Boolean,
19+
private val formatter: FormatterAction?
20+
) : BaseVisualControl<String>(initialText) {
2021

21-
val text = state(initialText)
2222
val error = state<String>()
2323

24-
val actionChangeText = action<String>()
24+
override fun transformObservable(
25+
observable: Observable<String>
26+
): Observable<String> = observable
27+
.map { s -> formatter?.let { it(s) } ?: s }
2528

26-
init {
27-
actionChangeText
28-
.observable
29-
.filter { it != text.value }
30-
.map { s -> formatter?.let { it(s) } ?: s }
31-
.subscribe {
32-
text.consumer.accept(it)
33-
if (hideErrorOnUserInput) error.consumer.accept("")
34-
}
29+
override fun onChangedValue(newValue: String) {
30+
super.onChangedValue(newValue)
31+
if (hideErrorOnUserInput) error.consumer.accept("")
3532
}
3633

3734
}
@@ -51,7 +48,12 @@ private val EditText.textChanges: Observable<CharSequence>
5148
/* nothing */
5249
}
5350

54-
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
51+
override fun beforeTextChanged(
52+
s: CharSequence?,
53+
start: Int,
54+
count: Int,
55+
after: Int
56+
) {
5557
/* nothing */
5658
}
5759

@@ -65,12 +67,14 @@ private val EditText.textChanges: Observable<CharSequence>
6567

6668
fun InputControl.bindTo(
6769
editText: EditText,
68-
useError: Boolean = false
70+
useError: Boolean = false,
71+
invisibleState: Int = View.GONE
6972
): Disposable {
7073
var editing = false
7174
return CompositeDisposable().apply {
75+
add(commonBindTo(editText, invisibleState))
7276
add(
73-
text
77+
value
7478
.observable
7579
.observeOn(AndroidSchedulers.mainThread())
7680
.subscribe {
@@ -103,16 +107,17 @@ fun InputControl.bindTo(
103107
.textChanges
104108
.filter { !editing }
105109
.map { it.toString() }
106-
.subscribe(actionChangeText.consumer)
110+
.subscribe(actionChangeValue.consumer)
107111
)
108112
}
109113
}
110114

111115
fun InputControl.bindTo(
112116
textInputLayout: TextInputLayout,
113-
useError: Boolean = false
117+
useError: Boolean = false,
118+
invisibleState: Int = View.GONE
114119
): Disposable = CompositeDisposable().apply {
115-
add(bindTo(textInputLayout.editText!!, false))
120+
add(bindTo(textInputLayout.editText!!, false, invisibleState))
116121
if (useError) {
117122
add(
118123
error
Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.alexdeww.reactiveviewmodel.widget
22

33
import android.annotation.SuppressLint
4+
import android.view.View
45
import android.widget.RatingBar
56
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
67
import io.reactivex.rxjava3.core.Observable
@@ -10,20 +11,7 @@ import io.reactivex.rxjava3.disposables.Disposable
1011
@SuppressLint("CheckResult")
1112
class RatingControl internal constructor(
1213
initialValue: Float
13-
) : BaseControl() {
14-
15-
val rating = state(initialValue)
16-
17-
val actionChange = action<Float>()
18-
19-
init {
20-
actionChange
21-
.observable
22-
.filter { it != rating.value }
23-
.subscribe { rating.consumer.accept(it) }
24-
}
25-
26-
}
14+
) : BaseVisualControl<Float>(initialValue)
2715

2816
fun ratingControl(initialValue: Float = 0f): RatingControl = RatingControl(initialValue)
2917

@@ -34,11 +22,15 @@ private val RatingBar.ratingBarChange: Observable<Float>
3422
emitter.setCancellable { onRatingBarChangeListener = null }
3523
}
3624

37-
fun RatingControl.bindTo(ratingBar: RatingBar): Disposable {
25+
fun RatingControl.bindTo(
26+
ratingBar: RatingBar,
27+
invisibleState: Int = View.GONE
28+
): Disposable {
3829
var editing = false
3930
return CompositeDisposable().apply {
31+
add(commonBindTo(ratingBar, invisibleState))
4032
add(
41-
rating
33+
value
4234
.observable
4335
.observeOn(AndroidSchedulers.mainThread())
4436
.subscribe {
@@ -52,7 +44,7 @@ fun RatingControl.bindTo(ratingBar: RatingBar): Disposable {
5244
ratingBar
5345
.ratingBarChange
5446
.filter { !editing }
55-
.subscribe(actionChange.consumer)
47+
.subscribe(actionChangeValue.consumer)
5648
)
5749
}
5850
}

0 commit comments

Comments
 (0)