Skip to content

Commit bfa2379

Browse files
authored
Merge pull request #20 from lucassales2/lusa/vmextensions
View model tag extensions
2 parents f941caf + 48d2c30 commit bfa2379

File tree

4 files changed

+94
-23
lines changed

4 files changed

+94
-23
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.monstarlab.arch.extensions
2+
3+
interface ViewErrorAware
4+
5+
interface LoadingAware
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Package set to androidx.lifecycle so we can have access to package private methods
2+
3+
package androidx.lifecycle
4+
5+
import com.monstarlab.arch.extensions.LoadingAware
6+
import com.monstarlab.arch.extensions.UseCaseResult
7+
import com.monstarlab.arch.extensions.ViewErrorAware
8+
import com.monstarlab.arch.extensions.onError
9+
import com.monstarlab.core.sharedui.errorhandling.ViewError
10+
import com.monstarlab.core.sharedui.errorhandling.mapToViewError
11+
import kotlinx.coroutines.flow.*
12+
import kotlinx.coroutines.launch
13+
14+
private const val ERROR_FLOW_KEY = "androidx.lifecycle.ErrorFlow"
15+
private const val LOADING_FLOW_KEY = "androidx.lifecycle.LoadingFlow"
16+
17+
fun <T> T.sendViewError(viewError: ViewError) where T : ViewErrorAware, T : ViewModel {
18+
viewModelScope.launch {
19+
getErrorMutableSharedFlow().emit(viewError)
20+
}
21+
}
22+
23+
suspend fun <T> T.emitViewError(viewError: ViewError) where T : ViewErrorAware, T : ViewModel {
24+
getErrorMutableSharedFlow().emit(viewError)
25+
}
26+
27+
val <T> T.viewErrorFlow: SharedFlow<ViewError> where T : ViewErrorAware, T : ViewModel
28+
get() {
29+
return getErrorMutableSharedFlow()
30+
}
31+
32+
33+
val <T> T.loadingFlow: StateFlow<Boolean> where T : LoadingAware, T : ViewModel
34+
get() {
35+
return loadingMutableStateFlow
36+
}
37+
38+
var <T> T.isLoading: Boolean where T : LoadingAware, T : ViewModel
39+
get() {
40+
return loadingMutableStateFlow.value
41+
}
42+
set(value) {
43+
loadingMutableStateFlow.tryEmit(value)
44+
}
45+
46+
private val <T> T.loadingMutableStateFlow: MutableStateFlow<Boolean> where T : LoadingAware, T : ViewModel
47+
get() {
48+
val flow: MutableStateFlow<Boolean>? = getTag(LOADING_FLOW_KEY)
49+
return flow ?: setTagIfAbsent(LOADING_FLOW_KEY, MutableStateFlow(false))
50+
}
51+
52+
private fun <T> T.getErrorMutableSharedFlow(): MutableSharedFlow<ViewError> where T : ViewErrorAware, T : ViewModel {
53+
val flow: MutableSharedFlow<ViewError>? = getTag(ERROR_FLOW_KEY)
54+
return flow ?: setTagIfAbsent(ERROR_FLOW_KEY, MutableSharedFlow())
55+
}
56+
57+
fun <F, T> Flow<F>.bindLoading(t: T): Flow<F> where T : LoadingAware, T : ViewModel {
58+
return this
59+
.onStart {
60+
t.loadingMutableStateFlow.value = true
61+
}
62+
.onCompletion {
63+
t.loadingMutableStateFlow.value = false
64+
}
65+
}
66+
67+
fun <F, T> Flow<UseCaseResult<F>>.bindError(t: T): Flow<UseCaseResult<F>> where T : ViewErrorAware, T : ViewModel {
68+
return this
69+
.onError {
70+
t.emitViewError(it.mapToViewError())
71+
}
72+
}
73+
74+
75+

app/src/main/java/com/monstarlab/features/login/LoginFragment.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import android.os.Bundle
44
import android.view.View
55
import androidx.core.view.isVisible
66
import androidx.lifecycle.lifecycleScope
7+
import androidx.lifecycle.loadingFlow
8+
import androidx.lifecycle.viewErrorFlow
79
import androidx.navigation.fragment.findNavController
810
import androidx.transition.TransitionManager
911
import com.google.android.material.snackbar.Snackbar
@@ -37,7 +39,6 @@ class LoginFragment : BaseFragment(R.layout.fragment_login) {
3739
}
3840

3941
snackErrorFlow(viewModel.errorFlow, view)
40-
4142
visibilityFlow(viewModel.loadingFlow, binding.loginProgressBar)
4243

4344
collectFlow(viewModel.loadingFlow) { loading ->
Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
11
package com.monstarlab.features.login
22

3-
import androidx.lifecycle.ViewModel
4-
import androidx.lifecycle.viewModelScope
5-
import com.monstarlab.arch.extensions.combineFlows
6-
import com.monstarlab.arch.extensions.onError
3+
import androidx.lifecycle.*
4+
import com.monstarlab.arch.extensions.LoadingAware
5+
import com.monstarlab.arch.extensions.ViewErrorAware
76
import com.monstarlab.arch.extensions.onSuccess
8-
import com.monstarlab.core.sharedui.errorhandling.ViewError
9-
import com.monstarlab.core.sharedui.errorhandling.mapToViewError
10-
import com.monstarlab.core.usecases.resources.GetResourcesUseCase
117
import com.monstarlab.core.usecases.user.LoginUseCase
12-
import kotlinx.coroutines.flow.*
8+
import kotlinx.coroutines.flow.MutableSharedFlow
9+
import kotlinx.coroutines.flow.launchIn
1310
import javax.inject.Inject
1411

1512
class LoginViewModel @Inject constructor(
16-
private val loginUseCase: LoginUseCase,
17-
private val getResourcesUseCase: GetResourcesUseCase
18-
): ViewModel() {
13+
private val loginUseCase: LoginUseCase
14+
) : ViewModel(), ViewErrorAware, LoadingAware {
1915

20-
val loadingFlow: MutableStateFlow<Boolean> = MutableStateFlow(false)
21-
val errorFlow: MutableSharedFlow<ViewError> = MutableSharedFlow()
2216
val loginResultFlow: MutableSharedFlow<Boolean> = MutableSharedFlow()
2317

2418
fun login(email: String, password: String) {
2519
loginUseCase
2620
.login(email, password)
27-
.onStart {
28-
loadingFlow.value = true
29-
}.onSuccess {
21+
.bindLoading(this)
22+
.bindError(this)
23+
.onSuccess {
3024
loginResultFlow.emit(true)
31-
}.onError {
32-
errorFlow.emit(it.mapToViewError())
33-
}.onCompletion {
34-
loadingFlow.value = false
35-
}.launchIn(viewModelScope)
25+
}
26+
.launchIn(viewModelScope)
3627
}
37-
3828
}

0 commit comments

Comments
 (0)