Meteor is a simple framework that helps you to create application using the MVI architecture.
APACHE-2.0 License
Meteor is a simple framework that helps you to create application using the MVI architecture. It provides a robust structure for organizing your code and separating concerns. Additionally, Meteor integrates with Kotlin Coroutine that helps you to write asynchronous and concurrent code.
Add the dependency below into your module's build.gradle.kts
file:
// It includes viewmodel, stateflow and core components.
implementation("io.github.behzodhalil:meteor-mvi:<latest-version>")
// If only need common use case
implementation("io.github.behzodhalil:meteor-usecase:<latest-version>")
// For testing
testImplementation("io.github.behzodhalil:meteor-test:<latest-version>")
data class CountState(
val count: Int = 0
)
sealed interface CountWish {
object Increase : CountWish
object Decrease : CountWish
object Reset : CountWish
object ZeroValue : CountWish
}
sealed interface CountEffect {
data class Failure(val message: String) : CountEffect
}
State
represents the current state of your application. Effects
are a way to handle side effects in Meteor. Side effects can include operations such as making network requests, updating a database, displaying UI messages, or triggering external actions. A Wish
in Meteor represents an action or an intention to change the state of the application.
Define a ViewModel class, such as MainViewModel
, that extends CommonViewModel
with the appropriate state, wish, and effect types:
class MainViewModel : CommonViewModel<CountState, CountWish, CountEffect>() {
// ....
}
Inside your ViewModel, override the store property by creating a Meteor
store using the createMeteor
function and providing the necessary configurations:
override val store: Store<CountState, CountWish, CountEffect> = createMeteor(
configs = MeteorConfigs.build {
initialState = CountState.Empty
storeName = "MainViewModel"
reducer = CountReducer
middleware = CountMiddleware
}
)
Define properties for effect and state in your ViewModel, which will expose the effect and state as CommonFlow
and CommonStateFlow
, respectively:
val effect: NonNullCommonFlow<CountEffect> = store.effect.asCommonFlow()
val state: NonNullCommonStateFlow<CountState> = store.state.asCommonStateFlow()
Create an object / class , such as CountReducer
, that implements the Reducer
interface with the appropriate state, wish, and effect types:
object CountReducer : Reducer<CountState, CountWish, CountEffect> {
override fun reduce(state: CountState, wish: CountWish): Change<CountState, CountEffect> {
return when (wish) {
CountWish.Decrease -> {
expect { state.copy(count = state.count - 1) }
}
CountWish.Increase -> {
expect { state.copy(count = state.count + 1) }
}
CountWish.Reset -> {
expect { state.copy(count = 0) }
}
CountWish.ZeroValue -> {
effect {
CountEffect.Failure("The value is zero")
}
}
}
}
}
viewModel.state.onEach { state ->
// Handle the state
}.launchIn(lifecycleScope)
viewModel.effect.onEach { effect ->
// Handle the effect, such as displaying a toast message or triggering an action
}.launchIn(lifecycleScope)
This project is licensed under the Apache License, Version 2.0 - see the license file for details