Last active
February 24, 2025 19:49
-
-
Save mahdiPourkazemi/d84503347d7633ace186c01e5c3c519d to your computer and use it in GitHub Desktop.
I think using use-case with mvi in this approach is better (model A vs model B) #android #kotlin #mvvm #mvi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.runtime.Composable | |
import androidx.compose.ui.Modifier | |
import androidx.lifecycle.ViewModel | |
import androidx.lifecycle.viewModelScope | |
import kotlinx.coroutines.flow.MutableStateFlow | |
import kotlinx.coroutines.flow.SharingStarted | |
import kotlinx.coroutines.flow.asStateFlow | |
import kotlinx.coroutines.flow.combine | |
import kotlinx.coroutines.flow.distinctUntilChangedBy | |
import kotlinx.coroutines.flow.launchIn | |
import kotlinx.coroutines.flow.map | |
import kotlinx.coroutines.flow.onEach | |
import kotlinx.coroutines.flow.stateIn | |
import kotlinx.coroutines.flow.update | |
// ViewModelA follows the MVVM (Model-View-ViewModel) architecture | |
class ViewModelA : ViewModel() { | |
private val _email = MutableStateFlow("") | |
val email = _email.asStateFlow() | |
private val _password = MutableStateFlow("") | |
val password = _password.asStateFlow() | |
fun updateEmail(email: String) { | |
_email.update { email } | |
} | |
fun updatePassword(password: String) { | |
_password.update { password } | |
} | |
// Validate email format | |
val isEmailValid = email | |
.map { it.isValidEmail() } | |
.stateIn( | |
viewModelScope, | |
SharingStarted.WhileSubscribed(5000), | |
false | |
) | |
// Validate password format | |
val isPasswordValid = password | |
.map { it.isValidPassword() } | |
.stateIn( | |
viewModelScope, | |
SharingStarted.WhileSubscribed(5000), | |
false | |
) | |
// Determine if registration is possible | |
val canRegister = combine(isEmailValid, isPasswordValid) { emailValid, passwordValid -> | |
emailValid && passwordValid | |
}.stateIn( | |
viewModelScope, | |
SharingStarted.WhileSubscribed(5000), | |
false | |
) | |
} | |
//////////////////////////////////////////////////////////////////////////// | |
// Define the state for MVI (Model-View-Intent) architecture | |
data class RegisterState( | |
val email: String = "", | |
val password: String = "", | |
val isEmailValid: Boolean = false, | |
val isPasswordValid: Boolean = false, | |
val canRegister: Boolean = false | |
) | |
// ViewModelB follows the MVI (Model-View-Intent) architecture | |
class ViewModelB : ViewModel() { | |
private val _state = MutableStateFlow(RegisterState()) | |
val state = _state.asStateFlow() | |
fun updateEmail(email: String) { | |
_state.update { it.copy(email = email) } | |
} | |
fun updatePassword(password: String) { | |
_state.update { it.copy(password = password) } | |
} | |
init { | |
// Email validation | |
state | |
.distinctUntilChangedBy { it.email } | |
.map { it.email.isValidEmail() } | |
.onEach { isEmailValid -> | |
_state.update { it.copy(isEmailValid = isEmailValid) } | |
} | |
.launchIn(viewModelScope) | |
// Password validation | |
state | |
.distinctUntilChangedBy { it.password } | |
.map { it.password.isValidPassword() } | |
.onEach { isPasswordValid -> | |
_state.update { it.copy(isPasswordValid = isPasswordValid) } | |
} | |
.launchIn(viewModelScope) | |
// Determine if registration is possible | |
state | |
.onEach { currentState -> | |
_state.update { | |
it.copy(canRegister = currentState.isEmailValid && currentState.isPasswordValid) | |
} | |
} | |
.launchIn(viewModelScope) | |
} | |
} | |
// UI for MVVM approach | |
@Composable | |
fun RegisterScreenA( | |
viewModel: ViewModelA, | |
modifier: Modifier = Modifier | |
) { | |
val email by viewModel.email.collectAsState() | |
val password by viewModel.password.collectAsState() | |
val canRegister by viewModel.canRegister.collectAsState() | |
// Implement UI here | |
} | |
// UI for MVI approach | |
val state by viewModel.state.collectAsState() // Do this in activity and pass it to the Composable below | |
// Implement the UI using state | |
@Composable | |
fun RegisterScreenB( | |
registerState: RegisterState, | |
modifier: Modifier = Modifier | |
) { | |
// Use registerState instead of viewModel | |
} | |
// Sample validation functions (for testing purposes) | |
fun String.isValidEmail(): Boolean = this.contains("@") && this.length > 5 | |
fun String.isValidPassword(): Boolean = this.length >= 8 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment