Skip to content

Commit 2e36385

Browse files
committed
update(add): showing error after EditText's text changed
1 parent 5fc367a commit 2e36385

File tree

4 files changed

+86
-17
lines changed

4 files changed

+86
-17
lines changed

app/src/main/java/com/hoc/flowmvi/FlowBinding+Exts+Utils.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.graphics.Color
66
import android.graphics.drawable.ColorDrawable
77
import android.text.Editable
88
import android.text.TextWatcher
9+
import android.util.Log
910
import android.view.View
1011
import android.widget.EditText
1112
import android.widget.Toast
@@ -19,6 +20,27 @@ import kotlinx.coroutines.channels.awaitClose
1920
import kotlinx.coroutines.flow.*
2021
import java.util.concurrent.atomic.AtomicBoolean
2122
import java.util.concurrent.atomic.AtomicReference
23+
import kotlin.coroutines.EmptyCoroutineContext
24+
25+
@ExperimentalCoroutinesApi
26+
fun EditText.firstChange(): Flow<Unit> {
27+
return callbackFlow<Unit> {
28+
val listener = object : TextWatcher {
29+
override fun afterTextChanged(s: Editable?) = Unit
30+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
31+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
32+
offer(Unit)
33+
}
34+
}.also { addTextChangedListener(it) }
35+
36+
awaitClose {
37+
Dispatchers.Main.dispatch(EmptyCoroutineContext) {
38+
removeTextChangedListener(listener)
39+
Log.d("###", "removeTextChangedListener $listener ${this@firstChange}")
40+
}
41+
}
42+
}.take(1)
43+
}
2244

2345
@ExperimentalCoroutinesApi
2446
@CheckResult

app/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.transition.AutoTransition
1010
import androidx.transition.TransitionManager
1111
import com.hoc.flowmvi.clicks
1212
import com.hoc.flowmvi.databinding.ActivityAddBinding
13+
import com.hoc.flowmvi.firstChange
1314
import com.hoc.flowmvi.textChanges
1415
import com.hoc.flowmvi.toast
1516
import com.hoc.flowmvi.ui.add.AddContract.*
@@ -81,7 +82,7 @@ class AddActivity : AppCompatActivity(), View {
8182
} else {
8283
null
8384
}
84-
if (addBinding.emailEditText.error != emailErrorMessage) {
85+
if (viewState.emailChanged && addBinding.emailEditText.error != emailErrorMessage) {
8586
addBinding.emailEditText.error = emailErrorMessage
8687
}
8788

@@ -90,7 +91,7 @@ class AddActivity : AppCompatActivity(), View {
9091
} else {
9192
null
9293
}
93-
if (addBinding.firstNameEditText.error != firstNameErrorMessage) {
94+
if (viewState.firstNameChanged && addBinding.firstNameEditText.error != firstNameErrorMessage) {
9495
addBinding.firstNameEditText.error = firstNameErrorMessage
9596
}
9697

@@ -99,7 +100,7 @@ class AddActivity : AppCompatActivity(), View {
99100
} else {
100101
null
101102
}
102-
if (addBinding.lastNameEditText.error != lastNameErrorMessage) {
103+
if (viewState.lastNameChanged && addBinding.lastNameEditText.error != lastNameErrorMessage) {
103104
addBinding.lastNameEditText.error = lastNameErrorMessage
104105
}
105106

@@ -116,27 +117,35 @@ class AddActivity : AppCompatActivity(), View {
116117

117118
private fun setupViews() = Unit
118119

119-
override fun intents(): Flow<ViewIntent> {
120-
return merge(
121-
addBinding
122-
.emailEditText
120+
override fun intents(): Flow<ViewIntent> = addBinding.run {
121+
merge(
122+
emailEditText
123123
.editText!!
124124
.textChanges()
125125
.map { ViewIntent.EmailChanged(it?.toString()) },
126-
addBinding
127-
.firstNameEditText
126+
firstNameEditText
128127
.editText!!
129128
.textChanges()
130129
.map { ViewIntent.FirstNameChanged(it?.toString()) },
131-
addBinding
132-
.lastNameEditText
130+
lastNameEditText
133131
.editText!!
134132
.textChanges()
135133
.map { ViewIntent.LastNameChanged(it?.toString()) },
136-
addBinding
137-
.addButton
134+
addButton
138135
.clicks()
139-
.map { ViewIntent.Submit }
136+
.map { ViewIntent.Submit },
137+
emailEditText
138+
.editText!!
139+
.firstChange()
140+
.map { ViewIntent.EmailChangedFirstTime },
141+
firstNameEditText
142+
.editText!!
143+
.firstChange()
144+
.map { ViewIntent.FirstNameChangedFirstTime },
145+
lastNameEditText
146+
.editText!!
147+
.firstChange()
148+
.map { ViewIntent.LastNameChangedFirstTime },
140149
)
141150
}
142151
}

app/src/main/java/com/hoc/flowmvi/ui/add/AddContract.kt

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@ interface AddContract {
1616

1717
data class ViewState(
1818
val errors: Set<ValidationError>,
19-
val isLoading: Boolean
19+
val isLoading: Boolean,
20+
val emailChanged: Boolean,
21+
val firstNameChanged: Boolean,
22+
val lastNameChanged: Boolean,
2023
) {
2124
companion object {
2225
fun initial() = ViewState(
2326
errors = emptySet(),
24-
isLoading = false
27+
isLoading = false,
28+
emailChanged = false,
29+
firstNameChanged = false,
30+
lastNameChanged = false,
2531
)
2632
}
2733
}
@@ -30,7 +36,12 @@ interface AddContract {
3036
data class EmailChanged(val email: String?) : ViewIntent()
3137
data class FirstNameChanged(val firstName: String?) : ViewIntent()
3238
data class LastNameChanged(val lastName: String?) : ViewIntent()
39+
3340
object Submit : ViewIntent()
41+
42+
object EmailChangedFirstTime : ViewIntent()
43+
object FirstNameChangedFirstTime : ViewIntent()
44+
object LastNameChangedFirstTime : ViewIntent()
3445
}
3546

3647
sealed class PartialStateChange {
@@ -53,6 +64,20 @@ interface AddContract {
5364
}
5465
}
5566
}
67+
68+
sealed class FirstChange : PartialStateChange() {
69+
object EmailChangedFirstTime : FirstChange()
70+
object FirstNameChangedFirstTime : FirstChange()
71+
object LastNameChangedFirstTime : FirstChange()
72+
73+
override fun reduce(viewState: ViewState): ViewState {
74+
return when (this) {
75+
EmailChangedFirstTime -> viewState.copy(emailChanged = true)
76+
FirstNameChangedFirstTime -> viewState.copy(firstNameChanged = true)
77+
LastNameChangedFirstTime -> viewState.copy(lastNameChanged = true)
78+
}
79+
}
80+
}
5681
}
5782

5883
sealed class SingleEvent {

app/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class AddVM(private val addUser: AddUserUseCase) : ViewModel() {
5252
change.user,
5353
change.throwable
5454
)
55+
PartialStateChange.FirstChange.EmailChangedFirstTime -> return@onEach
56+
PartialStateChange.FirstChange.FirstNameChangedFirstTime -> return@onEach
57+
PartialStateChange.FirstChange.LastNameChangedFirstTime -> return@onEach
5558
}
5659
_eventChannel.send(event)
5760
}
@@ -98,11 +101,21 @@ class AddVM(private val addUser: AddUserUseCase) : ViewModel() {
98101
.catch { emit(PartialStateChange.AddUser.AddUserFailure(user, it)) }
99102
}
100103

104+
val firstChanges = merge(
105+
filterIsInstance<ViewIntent.EmailChangedFirstTime>()
106+
.map { PartialStateChange.FirstChange.EmailChangedFirstTime },
107+
filterIsInstance<ViewIntent.FirstNameChangedFirstTime>()
108+
.map { PartialStateChange.FirstChange.FirstNameChangedFirstTime },
109+
filterIsInstance<ViewIntent.LastNameChangedFirstTime>()
110+
.map { PartialStateChange.FirstChange.LastNameChangedFirstTime }
111+
)
112+
101113
return merge(
102114
userFormFlow
103115
.map { it.errors }
104116
.map { PartialStateChange.ErrorsChanged(it) },
105-
addUserChanges
117+
addUserChanges,
118+
firstChanges,
106119
)
107120
}
108121

0 commit comments

Comments
 (0)