Skip to content

Instantly share code, notes, and snippets.

@mahdiPourkazemi
Last active February 24, 2025 19:49
Show Gist options
  • Save mahdiPourkazemi/d84503347d7633ace186c01e5c3c519d to your computer and use it in GitHub Desktop.
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
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