Why do you claim that UDF is a waste of time if you are still using it? Slightly different implementation details but, UDF none the less: Pass the state down and use callbacks (now one with event) for other component to handle
Nobody likes a bunch of callbacks, we can agree on that, but I find grouping lambdas into classes much simpler
data class LoginActions(
val onLoginButtonClicked: () -> Unit,
val onEmailChange: (String) -> Unit,
val onPasswordChange: (String) -> Unit
)
And there is no need for sealed classes and complex hierarchies, everything remains rather simple and can passed down with ease