Releases: hoc081098/kmp-viewmodel
0.8.0
Update dependencies
- Kotlin
2.0.0🎉. - AndroidX Lifecycle
2.8.1. - JetBrains Compose Multiplatform
1.6.11. - KotlinX Coroutines
1.8.1. - Touchlab Stately
2.0.7. - Koin Core
3.5.6, Koin Compose1.1.5.
kmp-viewmodel-savedstate
-
Added
JvmSerializable- multiplatform reference to Javajava.io.Serializableinterface,
along withNonNullSavedStateHandleKey.Companion.serializableandNullableSavedStateHandleKey.Companion.serializable// Use `JvmSerializable` with enum classes. enum class Gender : JvmSerializable { MALE, FEMALE, } // Create a `NonNullSavedStateHandleKey` for a serializable type. private val genderKey: NonNullSavedStateHandleKey<Gender> = NonNullSavedStateHandleKey.serializable( key = "gender", defaultValue = Gender.MALE, ) // Use `SavedStateHandle.safe` extension function to access `SavedStateHandle` in a type-safe way. val genderStateFlow: NonNullStateFlowWrapper<Gender> = savedStateHandle .safe { it.getStateFlow(genderKey) } .wrap()
-
Since Kotlin 2.0.0, you must add
"plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.hoc081098.kmp.viewmodel.parcelable.Parcelize"
as a free compiler argument to able to use@Parcelizeannotation in the common/shared module (Kotlin Multiplatform module).// build.gradle.kts plugins { id("kotlin-parcelize") // Apply the plugin for Android } // Since Kotlin 2.0.0, you must add the below code to your build.gradle.kts of the common/shared module (Kotlin Multiplatform module). kotlin { [...] // Other configurations targets.configureEach { val isAndroidTarget = platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm compilations.configureEach { compileTaskProvider.configure { compilerOptions { if (isAndroidTarget) { freeCompilerArgs.addAll( "-P", "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.hoc081098.kmp.viewmodel.parcelable.Parcelize", ) } } } } } }
0.7.1
kmp-viewmodel-compose
- JetBrains Compose Multiplatform
1.6.0. - New: Add support for Kotlin/Wasm (
wasmJstarget) 🎉.
Added kmp-viewmodel-koject and kmp-viewmodel-koject-compose artifacts
-
For more information check out the docs/0.x/viewmodel-koject-compose
-
The Koject dependency are used in
kmp-viewmodel-koject-compose:com.moriatsushi.koject:koject-core:1.3.0. -
New The
kmp-viewmodel-kojectartifact provides the integration ofkmp-viewmodel,kmp-viewmodel-composeandKoject,
helps us to retrieveViewModelfrom the Koject DI container without manually dependency injection.@Provides @Singleton class MyRepository @Provides @ViewModelComponent // <-- To inject SavedStateHandle class MyViewModel( val myRepository: MyRepository, val savedStateHandle: SavedStateHandle, ) : ViewModel() { // ... } @Composable fun MyScreen( viewModel: MyViewModel = kojectKmpViewModel(), ) { // ... }
Example, docs and tests
- Add Compose Multiplatform Koject sample
which sharesViewModels and integrates withNavigationin Compose Multiplatform. It usesKojectfor DI.
0.7.0
Update dependencies
- AndroidX Lifecycle
2.7.0. - Android target: update
Compile SDKandTarget SDKto34. - KotlinX Coroutines
1.8.0.
kmp-viewmodel and kmp-viewmodel-savedstate
- New: Add support for Kotlin/Wasm (
wasmJstarget) 🎉. - The behavior of
ViewModel.addCloseable(Closeable)on non-Android targets has been changed to be consistent with Android target.
ViewModel'saddCloseable()now immediately closes theCloseableif theViewModelhas been cleared.
This behavior is the same across all targets ✅.
kmp-viewmodel-koin
-
Fixed:
koinViewModelFactory:CreationExtraspassed toViewModelFactory.createwill now be
passed to the constructor of the ViewModel if it's requested.class MyViewModel(val extras: CreationExtras) : ViewModel() val myModule: Module = module { factoryOf(::MyViewModel) } val factory = koinViewModelFactory<MyViewModel>( scope = KoinPlatformTools.defaultContext().get().scopeRegistry.rootScope, ) val extras = buildCreationExtras { /* ... */ } val viewModel: MyViewModel = factory.create(extras) viewModel.extras === extras // true <--- `viewModel.extras` is the same as `extras` passed to `factory.create(extras)`
Example, docs and tests
- Add more tests to
kmp-viewmodel-compose(android & jvm),kmp-viewmodel-koin(common),
andkmp-viewmodel-koin-compose(common & jvm).
0.6.2
Update dependencies
Added kmp-viewmodel-koin and kmp-viewmodel-koin-compose artifacts
-
For more information check out the docs/0.x/viewmodel-koin-compose
-
The Koin dependencies are used in
kmp-viewmodel-koin-compose:io.insert-koin:koin-core:3.5.3.io.insert-koin:koin-compose:1.1.2.
-
New The
kmp-viewmodel-koinartifact provides the integration ofkmp-viewmodel,kmp-viewmodel-composeandKoin,
helps us to retrieveViewModelfrom the Koin DI container without manually dependency injection.class MyRepository class MyViewModel( val myRepository: MyRepository, val savedStateHandle: SavedStateHandle, val id: Int, ) : ViewModel() { // ... } val myModule: Module = module { factoryOf(::MyRepository) factoryOf(::MyViewModel) } @Composable fun MyScreen( id: Int, viewModel: MyViewModel = koinKmpViewModel( key = "MyViewModel-$id", parameters = { parametersOf(id) } ) ) { // ... }
Added type-safe API for SavedStateHandle
-
For more information check out the docs/0.x/viewmodel-savedstate-safe
-
New The
kmp-viewmodel-savedstateartifact provides the type-safe API
that allows you to accessSavedStateHandlein a type-safe way.private val searchTermKey: NonNullSavedStateHandleKey<String> = NonNullSavedStateHandleKey.string( key = "search_term", defaultValue = "" ) // Use `SavedStateHandle.safe` extension function to access `SavedStateHandle` in a type-safe way. savedStateHandle.safe { it[searchTermKey] = searchTerm } savedStateHandle.safe { it.getStateFlow(searchTermKey) } // Or use `SavedStateHandle.safe` extension property to access `SavedStateHandle` in a type-safe way. savedStateHandle.safe[searchTermKey] = searchTerm savedStateHandle.safe.getStateFlow(searchTermKey)
kmp-viewmodel-compose artifact
- New Add
rememberViewModelFactorys to remember theViewModelFactorys in@Composablefunctions.
They acceptbuilder: @DisallowComposableCalls CreationExtras.() -> VMs.
class MyViewModel(savedStateHandle: SavedStateHandle): ViewModel()
@Composable
fun MyScreen() {
val factory: ViewModelFactory<MyViewModel> = rememberViewModelFactory {
MyViewModel(savedStateHandle = createSavedStateHandle())
}
val viewModel: MyViewModel = kmpViewModel(factory = factory)
// ...
}-
New Add a new
kmpViewModeloverload that acceptsfactory: @DisallowComposableCalls CreationExtras.() -> VM
(Previously, it only acceptsfactory: ViewModelFactory<VM>).class MyViewModel(savedStateHandle: SavedStateHandle): ViewModel() @Composable fun MyScreen( viewModel: MyViewModel = kmpViewModel { MyViewModel(savedStateHandle = createSavedStateHandle()) } ) { // ... }
The above
kmpViewModelusesrememberViewModelFactoryinternally.
UserememberViewModelFactory { ... }andkmpViewModel(factory = factory)
is the same as usingkmpViewModel { ... }.
0.6.1
viewmodel
- On non-Android targets:
ViewModel.viewModelScopedoes not useDispatchers.Defaultas a fallback.
That means theCoroutineDispatcherofViewModel.viewModelScopeisDispatchers.Main.immediateorDispatchers.Main.
Example, docs
- Refactor example code.
- Add NOTE about the
kotlinx-coroutinesdependency when targetingDesktop(aka.jvm).
0.6.0
Update dependencies
Removed
- Remove now-unsupported targets:
iosArm32,watchosX86.
viewmodel
-
MutableCreationExtrashas been renamed toMutableCreationExtrasBuilder,
and it does not inherit fromCreationExtrasanymore.
Because of this, a new method
MutableCreationExtrasBuilder.asCreationExtras()has been introduced can be used to convert
a builder back toCreationExtrasas needed.NOTE:
buildCreationExtrasandCreationExtras.editmethods are still the same as before.// Old version (0.5.0) val creationExtras: CreationExtras = MutableCreationExtras().apply { // ... } // New version (0.6.0): `MutableCreationExtras` does not inherit from `CreationExtras` anymore. val creationExtras: CreationExtras = MutableCreationExtrasBuilder().apply { // ... }.asCreationExtras() // <--- asCreationExtras: convert a builder back to `CreationExtras` as needed.
More details: with Kotlin 1.9.20, an expect with default arguments are no longer
permitted when an actual is a typealias
(see KT-57614),
we cannot
useactual typealias MutableCreationExtras = androidx.lifecycle.viewmodel.MutableCreationExtras.
So we have to use wrapper class instead. -
Update the docs of
ViewModel.viewModelScopeto clarify that the scope is thread-safe
on both Android and non-Android targets. -
On non-Android targets
ViewModel.clear()method has been refactored to improve the performance.- Any
Exceptionthrown fromCloseable.close()will be re-thrown asRuntimeException.
0.5.0
Update dependencies
- Kotlin
1.9.0. - AndroidX Lifecycle
2.6.1. - KotlinX Coroutines
1.7.3. - Android Gradle Plugin
8.1.0.
viewmodel
- Add
ViewModelStoreandViewModelStoreOwner. - Add
ViewModelFactoryandVIEW_MODEL_KEY. - Add
CreationExtrasandCreationExtrasKey. - Add
buildCreationExtrasandCreationExtras.edit. - Add
ViewModel.isCleared()method to check if theViewModelis cleared, only available on
non-Android targets. - Add
MainThread(moved fromviewmodel-savedstatemodule).
viewmodel-savedstate
- Remove
MainThread(moved toviewmodelmodule). - Add
SavedStateHandleFactoryinterface. - Add
SAVED_STATE_HANDLE_FACTORY_KEYandCreationExtras.createSavedStateHandle().
viewmodel-compose
-
A new module allows to access
ViewModels in Jetpack Compose Multiplatform.kmpViewModelto retrieveViewModels in @composable functions.LocalSavedStateHandleFactoryandSavedStateHandleFactoryProviderto
get/provideSavedStateHandleFactoryin @composable functions.
It allows integration with any navigation library.LocalViewModelStoreOwnerandViewModelStoreOwnerProviderto
get/provideViewModelStoreOwnerin @composable functions.
It allows integration with any navigation library.defaultPlatformCreationExtrasanddefaultPlatformViewModelStoreOwner
to get the defaultCreationExtrasandViewModelStoreOwner,
which depends on the platform.
-
Dependencies: Compose Multiplatform 1.5.0.
-
Docs: 0.x Viewmodel-Compose docs.
Example, docs and tests
-
Refactor example code.
-
Add Compose Multiplatform sample
which sharesViewModels and integrates withNavigationin Compose Multiplatform. -
Add Compose Multiplatform KmpViewModel KMM Unsplash Sample,
a KMP template of the Unsplash App using Compose multiplatform for Android, Desktop, iOS.
Share everything including data, domain, presentation, and UI. -
Add more docs: 0.x docs.
-
Add more tests.
0.4.0
Changed
Update dependencies
- Kotlin
1.8.10. - Target
Java 11. - Touchlab Stately
1.2.5. - AndroidX Lifecycle
2.6.0. - Android Gradle Plugin
7.4.2.
Flow wrappers
-
Add
NonNullStateFlowWrapperandNullableFlowWrapperto common source set. -
Move all
Flowwrappers to common source set.
Previously, they were only available forDarwin targets(iOS,macOS,tvOS,watchOS). -
Add
Flow.wrap()extension methods to wrapFlows sources:Flow<T: Any>.wrap(): NonNullFlowWrapper<T>.Flow<T>.wrap(): NullableFlowWrapper<T>.StateFlow<T: Any>.wrap(): NonNullStateFlowWrapper<T>.StateFlow<T>.wrap(): NullableStateFlowWrapper<T>.
In common code, you can use these methods to wrap
Flowsources and use them in Swift code easily.// Kotlin code data class State(...) class SharedViewModel : ViewModel() { private val _state = MutableStateFlow(State(...)) val stateFlow: NonNullStateFlowWrapper<State> = _state.wrap() }
// Swift code @MainActor class IosViewModel: ObservableObject { private let vm: SharedViewModel @Published private(set) var state: State init(viewModel: SharedViewModel) { vm = viewModel state = vm.stateFlow.value // <--- Use `value` property with type safety (do not need to cast). vm.stateFlow.subscribe( // <--- Use `subscribe(scope:onValue:)` method directly. scope: vm.viewModelScope, onValue: { [weak self] in self?.state = $0 } ) } deinit { vm.clear() } }
Example, docs and tests
- Refactor example code.
- Add more docs: 0.x docs.
- Add more tests.
0.3.0
Added
- Add
NonNullFlowWrapperandNullableFlowWrapper, that are wrappers forFlows
that provides a more convenient API for subscribing to theFlows onDarwin targets(iOS,macOS,tvOS,watchOS)// Kotlin code val flow: StateFlow<Int>
// Swift code NonNullFlowWrapper<KotlinInt>(flow: flow).subscribe( scope: scope, onValue: { print("Received ", $0) } )
Changed
- Add more example, refactor example code.
- Add more docs: 0.x docs.
- Add more tests.
- Gradle
8.0.2. - Dokka
1.8.10.
0.2.0
Added
-
Add
kmp-viewmodel-savedstateartifact. This artifact brings:- Android Parcelable interface.
- The
@Parcelizeannotation
from kotlin-parcelize compiler plugin. - SavedStateHandle
class.
to Kotlin Multiplatform, so they can be used in common code.
This is typically used for state/data preservation
over Android configuration changes
and system-initiated process death
, when writing common code targeting Android.
Changed
- Add more example, refactor example code.
- Add more docs: 0.x docs.