Skip to content

Instantly share code, notes, and snippets.

@euri16
Created June 7, 2025 18:44
Show Gist options
  • Save euri16/0de7a3b1b470473e88324f046bf6461e to your computer and use it in GitHub Desktop.
Save euri16/0de7a3b1b470473e88324f046bf6461e to your computer and use it in GitHub Desktop.
sealed interface UserProfileEvent {
data object DeleteAccount : UserProfileEvent
data object ConsumeEffect : UserProfileEvent
}
sealed interface UserProfileEffect {
data class ShowError(val message: String) : UserProfileEffect
data object NavigateToLogin : UserProfileEffect
}
data class UserProfileUiState(
val isLoading: Boolean = false,
val user: User? = null,
val effect: UserProfileEffect? = null,
)
class UserProfileViewModel(
private val userRepository: UserRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(UserProfileUiState())
val uiState = _uiState.asStateFlow()
val effect = uiState.map { it.effect }
fun processEvent(event: UserProfileEvent) {
when (event) {
UserProfileEvent.DeleteAccount -> deleteAccount()
UserProfileEvent.ConsumeEffect -> consumeEffect()
}
}
private fun deleteAccount() {
viewModelScope.launch {
_uiState.update { it.copy(isLoading = true) }
try {
userRepository.deleteAccount()
_uiState.update {
it.copy(
isLoading = false,
effect = UserProfileEffect.NavigateToLogin
)
}
} catch (exception: Exception) {
_uiState.update {
it.copy(
isLoading = false,
effect = UserProfileEffect.ShowError(message = "An error occurred")
)
}
}
}
}
private fun consumeEffect() {
_uiState.update { it.copy(effect = null) }
}
}
// UI STARTS HERE
@Composable
fun UserProfileScreen(
viewModel: UserProfileViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Column {
Button(
onClick = { viewModel.processEvent(UserProfileEvent.DeleteAccount) },
enabled = uiState.isLoading.not()
) {
Text("Delete Account")
}
}
EffectHandler(viewModel.effect, onEvent = viewModel::processEvent)
}
@Composable
private fun EffectHandler(
effectFlow: Flow<UserProfileEffect?>,
navController: NavHostController = LocalNavHostController.current,
onEvent: (UserProfileEvent) -> Unit,
) {
LaunchedUiEffectHandler(
effectFlow,
onConsumeEffect = { onEvent(UserProfileEvent.ConsumeEffect) },
onEffect = { effect ->
when (effect) {
UserProfileEffect.NavigateToLogin -> {
navController.navigate(LoginRoute)
}
is UserProfileEffect.ShowError -> {
// Show error dialog or snackbar
showErrorDialog(effect.message)
}
}
}
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment