Skip to main content

Examples

This section provides examples of how to implement the adidas MVI library in your Android application. For more detail check the sample provided.

1. Login Flow Example

Here is a complete example of how to implement a login flow using the adidas MVI library.

ViewModel Implementation

The following code shows the LoginViewModel, which handles the login process.

class LoginViewModel(
logger: Logger,
coroutineDispatcher: CoroutineDispatcher = Dispatchers.Default
) : ViewModel(), MviHost<LoginIntent, State<LoginState, LoginSideEffect>> {

private val reducer = Reducer(
coroutineScope = viewModelScope,
defaultDispatcher = coroutineDispatcher,
initialInnerState = LoginState.LoggedOut(isLoggingIn = false),
logger = logger,
intentExecutor = this::executeIntent,
)

override val state = reducer.state

override fun execute(intent: LoginIntent) {
reducer.executeIntent(intent)
}

private fun executeIntent(intent: LoginIntent) =
when (intent) {
is LoginIntent.Login -> executeLogin(intent)
LoginIntent.Logout -> executeLogout()
LoginIntent.Close -> executeClose()
}

private fun executeLogin(intent: LoginIntent.Login) = flow {
emit(LoginTransform.SetIsLoggingIn(isLoggingIn = true))
delay(300) // Simulate a network call
emit(LoginTransform.SetIsLoggingIn(isLoggingIn = false))

if (intent.username.isEmpty() || intent.password.isEmpty()) {
emit(LoginTransform.AddSideEffect(LoginSideEffect.ShowInvalidCredentialsError))
} else {
emit(LoginTransform.SetLoggedIn(intent.username))
}
}
}

Intent Example

Define the intents that your application will handle:

internal sealed class LoginIntent : Intent {
data class Login(val username: String, val password: String) : LoginIntent()
object Logout : LoginIntent()
object Close : LoginIntent()
}

Activity Implementation

Here's how to set up the MviSampleActivity to use the LoginViewModel.

class MviSampleActivity : AppCompatActivity() {
private val viewModel: LoginViewModel by viewModel() // Assuming you're using Koin for dependency injection

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
LoginScreen(viewModel)
}
}
}

View Implementation

In your composable function, observe the state from the LoginViewModel and render the UI accordingly.

@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val state by viewModel.state.collectAsState()

when (state) {
is LoginState.LoggedOut -> {
// Show login UI
}
is LoginState.LoggedIn -> {
// Show logged-in UI
}
}
}