From 026fb5e78cb08ccab0f5cfd48f59494a8c5a1bb4 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Tue, 16 Jan 2024 16:05:34 -0300 Subject: [PATCH 01/77] Adding koin BOM doc --- docs/setup/koin.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 66c3e572e..80c28c5f8 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -198,3 +198,26 @@ fun Application.main() { :::info From now you can continue on Koin Tutorials to learn about using Koin: [Ktor App Tutorial](../quickstart/ktor) ::: + + +### **Koin BOM** +The Koin Bill of Materials (BOM) lets you manage all of your Koin library versions by specifying only the BOM’s version. The BOM itself has links to the stable versions of the different Koin libraries, in such a way that they work well together. When using the BOM in your app, you don't need to add any version to the Koin library dependencies themselves. When you update the BOM version, all the libraries that you're using are automatically updated to their new versions. + +```groovy +dependencies { + // Declare koin-bom version + implementation platform("io.insert-koin:koin-bom:$koin_bom") + + // Declare the koin dependencies that you need + implementation("io.insert-koin:koin-android") + implementation("io.insert-koin:koin-core-coroutines") + implementation("io.insert-koin:koin-androidx-workmanager") + + // If you need specify some version it's just point to desired version + implementation("io.insert-koin:koin-androidx-navigation:1.2.3-alpha03") + + // Works with test libraries too! + testImplementation("io.insert-koin:koin-test-junit4") + testImplementation("io.insert-koin:koin-android-test") +} +``` From 28cd859fbfbaedfc5b277ff3fa4af9b5d3443e2b Mon Sep 17 00:00:00 2001 From: Grzegorz Bobryk Date: Fri, 2 Feb 2024 15:18:58 +0100 Subject: [PATCH 02/77] [maintenance] bom added to versions table - row with bom version added to the table --- docs/setup/koin.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 66c3e572e..c4a5dc838 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -12,6 +12,7 @@ Here are the currently available versions: | Project | Version | |----------|:-------------:| +| koin-bom | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-bom)](https://mvnrepository.com/artifact/io.insert-koin/koin-bom) | | koin-core | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) | | koin-core-coroutines | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core-coroutines)](https://mvnrepository.com/artifact/io.insert-koin/koin-core-coroutines) | | koin-test | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-test)](https://mvnrepository.com/artifact/io.insert-koin/koin-test) | From 07f3041b62223f76f4d1620a1140792862d8e7c5 Mon Sep 17 00:00:00 2001 From: Grzegorz Bobryk Date: Fri, 2 Feb 2024 15:19:29 +0100 Subject: [PATCH 03/77] [maintenance] bom added to versions table - table reformatted --- docs/setup/koin.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index c4a5dc838..2a5c48479 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -10,22 +10,22 @@ You can find all Koin packages on [maven central](https://search.maven.org/searc Here are the currently available versions: -| Project | Version | -|----------|:-------------:| -| koin-bom | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-bom)](https://mvnrepository.com/artifact/io.insert-koin/koin-bom) | -| koin-core | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) | -| koin-core-coroutines | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core-coroutines)](https://mvnrepository.com/artifact/io.insert-koin/koin-core-coroutines) | -| koin-test | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-test)](https://mvnrepository.com/artifact/io.insert-koin/koin-test) | -| koin-android | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android)](https://mvnrepository.com/artifact/io.insert-koin/koin-android) | -| koin-android-test | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android-test)](https://mvnrepository.com/artifact/io.insert-koin/koin-android-test) | -| koin-android-compat | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android-compat)](https://mvnrepository.com/artifact/io.insert-koin/koin-android-compat) | -| koin-androidx-navigation | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-navigation)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-navigation) | -| koin-androidx-workmanager | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-workmanager)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-workmanager) | -| koin-compose | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-compose)](https://mvnrepository.com/artifact/io.insert-koin/koin-compose) | -| koin-androidx-compose | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-compose)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-compose) | -| koin-androidx-compose-navigation | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-compose-navigation)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-compose-navigation) | -| koin-ktor | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-ktor)](https://mvnrepository.com/artifact/io.insert-koin/koin-ktor) | -| koin-logger-slf4j | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-logger-slf4j)](https://mvnrepository.com/artifact/io.insert-koin/koin-logger-slf4j) | +| Project | Version | +|----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| koin-bom | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-bom)](https://mvnrepository.com/artifact/io.insert-koin/koin-bom) | +| koin-core | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core)](https://mvnrepository.com/artifact/io.insert-koin/koin-core) | +| koin-core-coroutines | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-core-coroutines)](https://mvnrepository.com/artifact/io.insert-koin/koin-core-coroutines) | +| koin-test | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-test)](https://mvnrepository.com/artifact/io.insert-koin/koin-test) | +| koin-android | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android)](https://mvnrepository.com/artifact/io.insert-koin/koin-android) | +| koin-android-test | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android-test)](https://mvnrepository.com/artifact/io.insert-koin/koin-android-test) | +| koin-android-compat | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-android-compat)](https://mvnrepository.com/artifact/io.insert-koin/koin-android-compat) | +| koin-androidx-navigation | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-navigation)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-navigation) | +| koin-androidx-workmanager | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-workmanager)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-workmanager) | +| koin-compose | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-compose)](https://mvnrepository.com/artifact/io.insert-koin/koin-compose) | +| koin-androidx-compose | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-compose)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-compose) | +| koin-androidx-compose-navigation | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-androidx-compose-navigation)](https://mvnrepository.com/artifact/io.insert-koin/koin-androidx-compose-navigation) | +| koin-ktor | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-ktor)](https://mvnrepository.com/artifact/io.insert-koin/koin-ktor) | +| koin-logger-slf4j | [![Maven Central](https://img.shields.io/maven-central/v/io.insert-koin/koin-logger-slf4j)](https://mvnrepository.com/artifact/io.insert-koin/koin-logger-slf4j) | ## Gradle Setup From 9194f93bad00c3b0e3504d1d41cee2239fd9dc44 Mon Sep 17 00:00:00 2001 From: Kevin Galligan Date: Thu, 15 Feb 2024 10:21:19 -0500 Subject: [PATCH 04/77] Bump version --- projects/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/gradle/libs.versions.toml b/projects/gradle/libs.versions.toml index 00036c9b5..ce120f137 100644 --- a/projects/gradle/libs.versions.toml +++ b/projects/gradle/libs.versions.toml @@ -23,7 +23,7 @@ composeJB = "1.5.11" composeJetpackRuntime = "1.5.4" composeJetpackViewmodel = "2.6.2" # Test -stately = "2.0.5" +stately = "2.0.6" junit = "4.13.2" jupiter = "5.9.3" mockito = "4.7.0" From 5c9bd1410b706b6094be0e9efef784cdcabad4d1 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:48:26 -0300 Subject: [PATCH 05/77] [DOC][FIX] Did you mean the adjective or adverb step-by-step (spelled with hyphens)? --- docs/resources/articles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/resources/articles.md b/docs/resources/articles.md index 323c74340..5f042cbe8 100644 --- a/docs/resources/articles.md +++ b/docs/resources/articles.md @@ -6,7 +6,7 @@ title: Articles * [Testing a Koin application with KotlinTest](https://dev.to/kerooker/testing-koin-applications-with-kotlintest-1iip) * [Ready for Koin 2.0](https://medium.com/koin-developers/ready-for-koin-2-0-2722ab59cac3) * [Migration from Dagger2 to Koin](https://proandroiddev.com/migrating-from-dagger2-to-koin-3b2b3f5285e9) -* [From Dagger to Koin, a step by step migration guide](https://medium.com/@giuliani.arnaud/the-thermosiphon-app-from-dagger-to-koin-step-by-step-a09af7f5b5b1) +* [From Dagger to Koin, a step-by-step migration guide](https://medium.com/@giuliani.arnaud/the-thermosiphon-app-from-dagger-to-koin-step-by-step-a09af7f5b5b1) * [Koin in Feature Modules Project](https://proandroiddev.com/koin-in-feature-modules-project-6329f069f943) * [A brief look at Koin on Android](https://overflow.buffer.com/2018/09/13/a-brief-look-at-koin-on-android/) * [Bye bye Dagger](https://medium.com/@charbgr/bye-bye-dagger-1494118dcd41) From 2c8d017e31b099d6e753604ab3c8d1adfe1c4aef Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:49:59 -0300 Subject: [PATCH 06/77] [DOC][FIX] Use an instead of 'a' if the following word starts with a vowel sound, e.g. 'an article', 'an hour'. --- docs/reference/koin-test/checkmodules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-test/checkmodules.md b/docs/reference/koin-test/checkmodules.md index 67e87494c..ddd43a5fe 100644 --- a/docs/reference/koin-test/checkmodules.md +++ b/docs/reference/koin-test/checkmodules.md @@ -252,7 +252,7 @@ fun `test DI modules`(){ } ``` -All injected definition that are using a injected `String` parameter, will receive `"_ID_"`: +All injected definition that are using an injected `String` parameter, will receive `"_ID_"`: ```kotlin module { From 35a4c21980a0ad506f01c8f45a84e265ca88d8fd Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:50:28 -0300 Subject: [PATCH 07/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/reference/koin-compose/compose.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/compose.md b/docs/reference/koin-compose/compose.md index 19b65fcd6..bcdad7b54 100644 --- a/docs/reference/koin-compose/compose.md +++ b/docs/reference/koin-compose/compose.md @@ -6,7 +6,7 @@ This page describe how you can inject your dependencies for your Jetpack Compose ## Starting Koin with Android Jetpack Compose - KoinApplication or KoinAndroidContext -Most of the time, `startKoin` function is used to start Koin in your application. This is done before running any Composable function. You need to setup Compose with your current Koin instance. Use `KoinAndroidContext()` to do so: +Most of the time, `startKoin` function is used to start Koin in your application. This is done before running any Composable function. You need to setting up Compose with your current Koin instance. Use `KoinAndroidContext()` to do so: ```kotlin @Composable From 2f77291a228605082ffbb4b5ca5ecebc5893b865 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:50:47 -0300 Subject: [PATCH 08/77] [DOC][FIX] This expression is usually spelled with a hyphen. --- docs/reference/koin-core/context-isolation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/context-isolation.md b/docs/reference/koin-core/context-isolation.md index e6dd63b74..bdf7dd253 100644 --- a/docs/reference/koin-core/context-isolation.md +++ b/docs/reference/koin-core/context-isolation.md @@ -3,7 +3,7 @@ title: Context Isolation --- -For SDK Makers, you can also work with Koin in a non global way: use Koin for the DI of your library and avoid any conflict by people using your library and Koin by isolating your context. +For SDK Makers, you can also work with Koin in a non-global way: use Koin for the DI of your library and avoid any conflict by people using your library and Koin by isolating your context. In a standard way, we can start Koin like that: From 56d8c57920f759258cb880de811ef63d1a3f80a6 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:52:02 -0300 Subject: [PATCH 09/77] [DOC][FIX] The modal verb 'will' requires the verb's base form. --- docs/reference/koin-core/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/definitions.md b/docs/reference/koin-core/definitions.md index da7556a67..08153cb34 100644 --- a/docs/reference/koin-core/definitions.md +++ b/docs/reference/koin-core/definitions.md @@ -41,7 +41,7 @@ The result type of your lambda is the main type of your component ## Defining a factory -A factory component declaration is a definition that will gives you a *new instance each time* you ask for this definition (this instance is not retained by Koin container, as it won't inject this instance in other definitions later). Use the `factory` function with a lambda expression to build a component. +A factory component declaration is a definition that will provide you a *new instance each time* you ask for this definition (this instance is not retained by Koin container, as it won't inject this instance in other definitions later). Use the `factory` function with a lambda expression to build a component. ```kotlin class Controller() From 81076b09186d2aef2df6cb6240c5bc2bd0fdb8d9 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:53:37 -0300 Subject: [PATCH 10/77] [DOC][FIX] A determiner cannot be combined with a possessive pronoun. Did you mean simply the or their? --- docs/reference/koin-core/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/definitions.md b/docs/reference/koin-core/definitions.md index 08153cb34..0ffdef3c3 100644 --- a/docs/reference/koin-core/definitions.md +++ b/docs/reference/koin-core/definitions.md @@ -84,7 +84,7 @@ val myModule = module { ## Definition: binding an interface -A `single` or a `factory` definition use the type from the their given lambda definition: i.e `single { T }` +A `single` or a `factory` definition use the type from their given lambda definition: i.e `single { T }` The matched type of the definition is the only matched type from this expression. Let's take an example with a class and implemented interface: From c160034a2a738e6788260a56f70099fe989e6d1c Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:54:25 -0300 Subject: [PATCH 11/77] [DOC][FIX] The abbreviation i.e. (= that is) requires two periods. --- docs/reference/koin-core/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/definitions.md b/docs/reference/koin-core/definitions.md index 0ffdef3c3..fe3138c51 100644 --- a/docs/reference/koin-core/definitions.md +++ b/docs/reference/koin-core/definitions.md @@ -84,7 +84,7 @@ val myModule = module { ## Definition: binding an interface -A `single` or a `factory` definition use the type from their given lambda definition: i.e `single { T }` +A `single` or a `factory` definition use the type from their given lambda definition i.e: `single { T }` The matched type of the definition is the only matched type from this expression. Let's take an example with a class and implemented interface: From 4b8042a7d7c835b4d10af9d049d516474c65f77c Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:54:53 -0300 Subject: [PATCH 12/77] [DOC][FIX] Did you mean 'as follows' --- docs/reference/koin-core/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/definitions.md b/docs/reference/koin-core/definitions.md index fe3138c51..59fef04d8 100644 --- a/docs/reference/koin-core/definitions.md +++ b/docs/reference/koin-core/definitions.md @@ -103,7 +103,7 @@ class ServiceImp() : Service { } ``` -In a Koin module we can use the `as` cast Kotlin operator as follow: +In a Koin module we can use the `as` cast Kotlin operator as follows: ```kotlin val myModule = module { From c415559e3fee8ff53629f36e3edffe4632b26aa3 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:55:13 -0300 Subject: [PATCH 13/77] [DOC][FIX] Adding missing comma --- docs/reference/koin-core/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/definitions.md b/docs/reference/koin-core/definitions.md index 59fef04d8..2fccae2ad 100644 --- a/docs/reference/koin-core/definitions.md +++ b/docs/reference/koin-core/definitions.md @@ -184,7 +184,7 @@ val service : Service by inject(qualifier = named("default")) `get()` and `by inject()` functions let you specify a definition name if needed. This name is a `qualifier` produced by the `named()` function. -By default Koin will bind a definition by its type or by its name, if the type is already bound to a definition. +By default, Koin will bind a definition by its type or by its name, if the type is already bound to a definition. ```kotlin val myModule = module { From 6386444c0657858a7a5b2dc31595a820b13f7c04 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:55:30 -0300 Subject: [PATCH 14/77] [DOC][FIX] Possible typo: you repeated a word --- docs/reference/koin-core/dsl-update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl-update.md b/docs/reference/koin-core/dsl-update.md index 74565c3a9..77a3417d3 100644 --- a/docs/reference/koin-core/dsl-update.md +++ b/docs/reference/koin-core/dsl-update.md @@ -2,7 +2,7 @@ title: Constructor DSL --- -Koin now offer a new kind of DSL keyword that allow you to target a class constructor directly, and avoid to to have type your definition within a lambda expression. +Koin now offer a new kind of DSL keyword that allow you to target a class constructor directly, and avoid to have type your definition within a lambda expression. For a given class `ClassA` with following dependencies: From c561bbf2e8529600870eee9f61c83261f6b97c87 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:55:47 -0300 Subject: [PATCH 15/77] [DOC][FIX] The usual preposition to use after "fill" is "with", not "every". Did you mean fill every parameter with? --- docs/reference/koin-core/dsl-update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl-update.md b/docs/reference/koin-core/dsl-update.md index 77a3417d3..fc04c3e9d 100644 --- a/docs/reference/koin-core/dsl-update.md +++ b/docs/reference/koin-core/dsl-update.md @@ -45,7 +45,7 @@ The following keywords are available to build your definition from constructor: * `scopedOf` - equivalent of `scoped { }` - scoped definition :::info -Be sure to not use any default value in your constructor, as Koin will try to fill every parameter of it. +Be sure to not use any default value in your constructor, as Koin will try to fill every parameter with it. ::: ## DSL Options From 9d233b9147d7160a93287e1c2b1cdc79cc524559 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:56:42 -0300 Subject: [PATCH 16/77] [DOC][FIX] Adding missing 'to' --- docs/reference/koin-core/dsl-update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl-update.md b/docs/reference/koin-core/dsl-update.md index fc04c3e9d..1c36ef3cc 100644 --- a/docs/reference/koin-core/dsl-update.md +++ b/docs/reference/koin-core/dsl-update.md @@ -71,7 +71,7 @@ Usual options and DSL keywords are available in this lambda: * `binds(listOf(...))` - add types list for given bean definition * `createdAtStart()` - create single instance at Koin start -You can also use `bind` or `binds` operator, without any need of lambda: +You can also to use `bind` or `binds` operator, without any need of lambda: ```kotlin module { From 7427ad5761a11b2177532e40698336c6f65dac82 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:57:04 -0300 Subject: [PATCH 17/77] [DOC][FIX] Did you mean to inject? --- docs/reference/koin-core/dsl-update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl-update.md b/docs/reference/koin-core/dsl-update.md index 1c36ef3cc..3efd152c3 100644 --- a/docs/reference/koin-core/dsl-update.md +++ b/docs/reference/koin-core/dsl-update.md @@ -81,7 +81,7 @@ module { ## Injected Parameters -With such kind of declaration, you can still use injected parameters. Koin will look in injected parameters and current dependencies to try inject your constructor. +With such kind of declaration, you can still use injected parameters. Koin will look in injected parameters and current dependencies to try to inject your constructor. Like following: From e347f9f424f2badf91d6bcba3cde848f52a878df Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:57:21 -0300 Subject: [PATCH 18/77] [DOC][FIX] Possible typo: you repeated a word --- docs/reference/koin-android/dsl-update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/dsl-update.md b/docs/reference/koin-android/dsl-update.md index 1b7842677..972911e48 100644 --- a/docs/reference/koin-android/dsl-update.md +++ b/docs/reference/koin-android/dsl-update.md @@ -4,7 +4,7 @@ title: Constructor DSL for Android ## New Constructor DSL (Since 3.2) -Koin now offer a new kind of DSL keyword that allow you to target a class constructor directly, and avoid to to have type your definition within a lambda expression. +Koin now offer a new kind of DSL keyword that allow you to target a class constructor directly, and avoid to have type your definition within a lambda expression. Check the new [Constructor DSL](../koin-core/dsl-update.md#constructor-dsl-since-32) section for more details. From 41e322ed389c6b625287d65e5c72350c412b219c Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:57:40 -0300 Subject: [PATCH 19/77] [DOC][FIX] Adding missing comma --- docs/reference/koin-core/dsl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl.md b/docs/reference/koin-core/dsl.md index 4fc0f12c9..2630eb48b 100644 --- a/docs/reference/koin-core/dsl.md +++ b/docs/reference/koin-core/dsl.md @@ -36,7 +36,7 @@ As you can see above, we can describe a Koin container configuration in 2 ways: - `koinApplication` describe a Koin container instance - `startKoin` describe a Koin container instance and register it in Koin `GlobalContext` -By registering your container configuration into the `GlobalContext`, the global API can use it directly. Any `KoinComponent` refers to a `Koin` instance. By default we use the one from `GlobalContext`. +By registering your container configuration into the `GlobalContext`, the global API can use it directly. Any `KoinComponent` refers to a `Koin` instance. By default, we use the one from `GlobalContext`. Check chapters about Custom Koin instance for more information. From 1d99180a3415aa931a081afa0675cc5850e4df36 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:58:17 -0300 Subject: [PATCH 20/77] [DOC][FIX] Moving to singular --- docs/reference/koin-core/dsl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/dsl.md b/docs/reference/koin-core/dsl.md index 2630eb48b..f5f54be31 100644 --- a/docs/reference/koin-core/dsl.md +++ b/docs/reference/koin-core/dsl.md @@ -70,7 +70,7 @@ To describe your content in a module, you can use the following functions: * `bind()` - add type to bind for given bean definition * `binds()` - add types array for given bean definition * `scope { // scope group }` - define a logical group for `scoped` definition -* `scoped { //definition }`- provide a bean definition that will exists only in a scope +* `scoped { //definition }`- provide a bean definition that will exist only in a scope Note: the `named()` function allow you to give a qualifier either by a string, an enum or a type. It is used to name your definitions. From 3e582ddf815743cc4dd937c56e60011318769e57 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:58:45 -0300 Subject: [PATCH 21/77] [DOC][FIX] Consider using either the past participle introduced or the present participle introducing here. --- docs/reference/koin-android/fragment-factory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/fragment-factory.md b/docs/reference/koin-android/fragment-factory.md index 94453a34b..30257dcfd 100644 --- a/docs/reference/koin-android/fragment-factory.md +++ b/docs/reference/koin-android/fragment-factory.md @@ -8,7 +8,7 @@ https://developer.android.com/jetpack/androidx/releases/fragment ## Fragment Factory -Since `2.1.0-alpha-3` version, has been introduce the `FragmentFactory`, a class dedicated to create instance of `Fragment` class: +Since `2.1.0-alpha-3` version, has been introduced the `FragmentFactory`, a class dedicated to create instance of `Fragment` class: https://developer.android.com/reference/kotlin/androidx/fragment/app/FragmentFactory From 60f71619a6edb470825f29ec2adafa4573bcaf57 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:59:17 -0300 Subject: [PATCH 22/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/reference/koin-android/fragment-factory.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/koin-android/fragment-factory.md b/docs/reference/koin-android/fragment-factory.md index 30257dcfd..8a9f2bc34 100644 --- a/docs/reference/koin-android/fragment-factory.md +++ b/docs/reference/koin-android/fragment-factory.md @@ -16,7 +16,7 @@ Koin can bring a `KoinFragmentFactory` to help you inject your `Fragment` instan ## Setup Fragment Factory -At start, in your KoinApplication declaration, use the `fragmentFactory()` keyword to setup a default `KoinFragmentFactory` instance: +At start, in your KoinApplication declaration, use the `fragmentFactory()` keyword to setting up a default `KoinFragmentFactory` instance: ```kotlin startKoin { @@ -49,7 +49,7 @@ val appModule = module { ## Get your Fragment -From your host `Activity` class, setup your fragment factory with `setupKoinFragmentFactory()`: +From your host `Activity` class, setting up your fragment factory with `setupKoinFragmentFactory()`: ```kotlin class MyActivity : AppCompatActivity() { @@ -95,7 +95,7 @@ val appModule = module { } ``` -and setup your Koin Fragment Factory with your scope: `setupKoinFragmentFactory(lifecycleScope)` +and setting up your Koin Fragment Factory with your scope: `setupKoinFragmentFactory(lifecycleScope)` ```kotlin class MyActivity : AppCompatActivity() { From 635d20aa4304af831eb4e63ca7e03298225736cd Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:59:38 -0300 Subject: [PATCH 23/77] [DOC][FIX] Use a comma before 'and' if it connects two independent clauses (unless they are closely connected and short). --- docs/reference/koin-android/get-instances.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/get-instances.md b/docs/reference/koin-android/get-instances.md index 4655f6394..e5f530806 100644 --- a/docs/reference/koin-android/get-instances.md +++ b/docs/reference/koin-android/get-instances.md @@ -3,7 +3,7 @@ title: Injecting in Android --- -Once you have declared some modules and you have started Koin, how can you retrieve your instances in your +Once you have declared some modules, and you have started Koin, how can you retrieve your instances in your Android Activity Fragments or Services? ## Ready for Android Classes From 196260b26f60b999a0adee158b51dbc0f688d734 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 22:59:51 -0300 Subject: [PATCH 24/77] [DOC][FIX] Did you mean as follows? --- docs/reference/koin-core/injection-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/injection-parameters.md b/docs/reference/koin-core/injection-parameters.md index ef0dc04d1..cfa28eb46 100644 --- a/docs/reference/koin-core/injection-parameters.md +++ b/docs/reference/koin-core/injection-parameters.md @@ -57,7 +57,7 @@ val myModule = module { ## Resolving injected parameters in order -Instead of using `get()` to resolve a parameter, if you have several parameters of the same type you can use the index as follow `get(index)` (also same as `[ ]` operator): +Instead of using `get()` to resolve a parameter, if you have several parameters of the same type you can use the index as follows `get(index)` (also same as `[ ]` operator): ```kotlin class Presenter(val view : View) From ae0e896c707b7f38be04e316158f983f0c094f6b Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:00:07 -0300 Subject: [PATCH 25/77] [DOC][FIX] The past participle is required after "will be". --- docs/reference/koin-core/injection-parameters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/injection-parameters.md b/docs/reference/koin-core/injection-parameters.md index cfa28eb46..94b3d9f49 100644 --- a/docs/reference/koin-core/injection-parameters.md +++ b/docs/reference/koin-core/injection-parameters.md @@ -85,7 +85,7 @@ val myModule = module { In addition to `parametersOf`, the following API are accessible: -- `parameterArrayOf`: to use an array of value, and data will be use by its index +- `parameterArrayOf`: to use an array of value, and data will be uses by its index ```kotlin val params = parameterArrayOf(1,2,3) From ebf1dd5796c68b8adb27075e3d370c8f261c5465 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:00:27 -0300 Subject: [PATCH 26/77] [DOC][FIX] Use an instead of 'a' if the following word starts with a vowel sound, e.g. 'an article', 'an hour'. --- docs/reference/koin-compose/isolated-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/isolated-context.md b/docs/reference/koin-compose/isolated-context.md index 384705694..0c55acd85 100644 --- a/docs/reference/koin-compose/isolated-context.md +++ b/docs/reference/koin-compose/isolated-context.md @@ -2,7 +2,7 @@ title: Isolated Context with Compose --- -With a Compose application, you can work the same way with an [isolated context](../koin-core/context-isolation.md) to deal with SDK or white label application, in order to not mix your Koin definitions with a end user's one. +With a Compose application, you can work the same way with an [isolated context](../koin-core/context-isolation.md) to deal with SDK or white label application, in order to not mix your Koin definitions with an end user's one. ## Define isolated context From 861f658b4f278e29c0cb7a9f7020361d639bf206 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:00:38 -0300 Subject: [PATCH 27/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/reference/koin-compose/isolated-context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/isolated-context.md b/docs/reference/koin-compose/isolated-context.md index 0c55acd85..f93654928 100644 --- a/docs/reference/koin-compose/isolated-context.md +++ b/docs/reference/koin-compose/isolated-context.md @@ -24,7 +24,7 @@ Adapt the `MyIsolatedKoinContext` class according your need of initialization ## Setup isolated context with Compose -Now that you have defined an isolated Koin context, we can setup it up to Compose to use it and override all the API. Just use the `KoinIsolatedContext` at the root Compose function. This will propagate your Koin context in all child composables. +Now that you have defined an isolated Koin context, we can seting up it up to Compose to use it and override all the API. Just use the `KoinIsolatedContext` at the root Compose function. This will propagate your Koin context in all child composables. ```kotlin @Composable From 99db4e5cde2dca35239c5d264e5a208a0f73e7f2 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:01:57 -0300 Subject: [PATCH 28/77] [DOC][FIX] The word 'init' is a noun or an adjective. A verb or adverb is missing or misspelled here, or maybe a comma is missing. --- docs/reference/koin-mp/kmp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-mp/kmp.md b/docs/reference/koin-mp/kmp.md index d5600e7ad..dd9cdfdb9 100644 --- a/docs/reference/koin-mp/kmp.md +++ b/docs/reference/koin-mp/kmp.md @@ -93,7 +93,7 @@ fun initKoin(){ } ``` -We can init it in our Main app entry: +We can initialize it in our Main app entry: ```kotlin @main From 35932021b603c479c757b07791cff2c193113aa8 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:02:11 -0300 Subject: [PATCH 29/77] [DOC][FIX] Removing empty spaces --- docs/reference/koin-mp/kmp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-mp/kmp.md b/docs/reference/koin-mp/kmp.md index dd9cdfdb9..c0348a3e1 100644 --- a/docs/reference/koin-mp/kmp.md +++ b/docs/reference/koin-mp/kmp.md @@ -99,7 +99,7 @@ We can initialize it in our Main app entry: @main struct iOSApp: App { - // KMM - Koin Call + // KMM - Koin Call init() { HelperKt.doInitKoin() } From 4234403c10a3fd05c222f41ac4e3d570f3d00c60 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:02:49 -0300 Subject: [PATCH 30/77] [DOC][FIX] This phrase is redundant. Consider using outside. --- docs/reference/koin-core/koin-component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/koin-component.md b/docs/reference/koin-core/koin-component.md index 1421bb880..976e70148 100644 --- a/docs/reference/koin-core/koin-component.md +++ b/docs/reference/koin-core/koin-component.md @@ -3,7 +3,7 @@ title: Koin Component --- Koin is a DSL to help describe your modules & definitions, a container to make definition resolution. What we need now is -an API to retrieve our instances outside of the container. That's the goal of Koin components. +an API to retrieve our instances outside the container. That's the goal of Koin components. :::info The `KoinComponent` interface is here to help you retrieve instances directly from Koin. Be careful, this links your class to the Koin container API. Avoid to use it on classes that you can declare in `modules`, and prefer constructor injection From 8ce5bdf11cb5fc6954aa11b18b53e99d2014b3fa Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:03:19 -0300 Subject: [PATCH 31/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/setup/koin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 2a5c48479..5bea31204 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -2,7 +2,7 @@ title: Koin --- -All you need to setup Koin in your project +All you need to setting up Koin in your project ## Current Versions From 6d664a6890781856274428ba40145354a561487d Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:03:37 -0300 Subject: [PATCH 32/77] [DOC][FIX] This phrase is redundant. Consider using outside. --- docs/reference/koin-ktor/ktor-isolated.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-ktor/ktor-isolated.md b/docs/reference/koin-ktor/ktor-isolated.md index 8312ba673..b4481244a 100644 --- a/docs/reference/koin-ktor/ktor-isolated.md +++ b/docs/reference/koin-ktor/ktor-isolated.md @@ -20,7 +20,7 @@ fun Application.main() { ``` :::warning - By using an isolated Koin context you won't be able to use Koin outside of Ktor server instance (i.e: by using `GlobalContext` for example) + By using an isolated Koin context you won't be able to use Koin outside Ktor server instance (i.e: by using `GlobalContext` for example) ::: From f27d8e5aad5b17a449c77377cee8bd3be38fa259 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:04:00 -0300 Subject: [PATCH 33/77] [DOC][FIX] Did you mean there? --- docs/upgrade/migrate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/upgrade/migrate.md b/docs/upgrade/migrate.md index 022da2406..751e5b5dd 100644 --- a/docs/upgrade/migrate.md +++ b/docs/upgrade/migrate.md @@ -10,7 +10,7 @@ The new branch of Koin 3.x is bringing latest features & fixes. It brings Multip #### Android & AndroidX Module -The following modules are available for Android. Be sure to use the `koin-androidx` modules, as their are based on the latest AndroidX library support: +The following modules are available for Android. Be sure to use the `koin-androidx` modules, as there are based on the latest AndroidX library support: ```groovy // Koin AndroidX Scope features From 2cd0ddbb9b7b80ecca6bf1d1529aa868ffb174e0 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:04:23 -0300 Subject: [PATCH 34/77] [DOC][FIX] A verb ('be' or 'have') is missing before the past participle. --- docs/upgrade/migrate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/upgrade/migrate.md b/docs/upgrade/migrate.md index 751e5b5dd..97418e102 100644 --- a/docs/upgrade/migrate.md +++ b/docs/upgrade/migrate.md @@ -33,7 +33,7 @@ The new Koin core is now Multiplatform. You can use it even if your project is n #### Reimporting for new API -If you seen unresolved Koin API import, you can try to remove/reimport the used API as some packages has been moved in the Koin core module. See new section +If you have seen unresolved Koin API import, you can try to remove/reimport the used API as some packages has been moved in the Koin core module. See new section #### Kotlin Core & JVM features From bf68dd774951cba6808fa1abdc4d85f71fb128c5 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:04:51 -0300 Subject: [PATCH 35/77] [DOC][FIX] Did you mean there? --- docs/upgrade/migrate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/upgrade/migrate.md b/docs/upgrade/migrate.md index 97418e102..44dbbd86e 100644 --- a/docs/upgrade/migrate.md +++ b/docs/upgrade/migrate.md @@ -57,7 +57,7 @@ Java/JVM Specific API are isolated in `koin-core-jvm` part of Koin core. Here ar #### Android Modules -In v3, the `koin-android` modules is using AndroidX API, and merge also all Scope/Fragment/ViewModel API. You don't need anymore to specify `koin-androidx-fragment`, `koin-androidx-viewmodel` or `koin-androidx-scope` as their are all in the `koin-android` module: +In v3, the `koin-android` modules is using AndroidX API, and merge also all Scope/Fragment/ViewModel API. You don't need anymore to specify `koin-androidx-fragment`, `koin-androidx-viewmodel` or `koin-androidx-scope` as there are all in the `koin-android` module: ```groovy // Koin main features for Android (Scope,ViewModel ...) From 251825dc659efff06a22b75009dcb16e240dd7cc Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:05:14 -0300 Subject: [PATCH 36/77] [DOC][FIX] Possible typo: you repeated a word --- docs/reference/koin-android/modules-android.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/modules-android.md b/docs/reference/koin-android/modules-android.md index 8c2773dba..72118547e 100644 --- a/docs/reference/koin-android/modules-android.md +++ b/docs/reference/koin-android/modules-android.md @@ -7,7 +7,7 @@ By using Koin, you describe definitions in modules. In this section we will see ## Using several modules Components doesn't have to be necessarily in the same module. A module is a logical space to help you organize your definitions, and can depend on definitions from other -module. Definitions are lazy, and then are resolved only when a a component is requesting it. +module. Definitions are lazy, and then are resolved only when a component is requesting it. Let's take an example, with linked components in separate modules: From a08159d14e98613a5e076a0a840a8904077df13c Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:05:32 -0300 Subject: [PATCH 37/77] [DOC][FIX] The modal verb 'can' requires the verb's base form. --- docs/reference/koin-android/modules-android.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/modules-android.md b/docs/reference/koin-android/modules-android.md index 72118547e..c5aeba0f8 100644 --- a/docs/reference/koin-android/modules-android.md +++ b/docs/reference/koin-android/modules-android.md @@ -124,7 +124,7 @@ Notice that all modules will be included only once: `dataModule`, `domainModule` ## Reducing Startup time with background module loading -You can now declared "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. This can help avoid to block Android starting process, by passing lazy modules to be loaded in background. +You can now declare "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. This can help avoid to block Android starting process, by passing lazy modules to be loaded in background. - `lazyModule` - declare a Lazy Kotlin version of Koin Module - `Module.includes` - allow to include lazy Modules From d096edb3a418803618b299726d6701ebc3d46884 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:05:45 -0300 Subject: [PATCH 38/77] [DOC][FIX] Possible typo: you repeated a word --- docs/reference/koin-core/modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/modules.md b/docs/reference/koin-core/modules.md index c84c5081d..dfb661456 100644 --- a/docs/reference/koin-core/modules.md +++ b/docs/reference/koin-core/modules.md @@ -17,7 +17,7 @@ val myModule = module { ## Using several modules Components doesn't have to be necessarily in the same module. A module is a logical space to help you organize your definitions, and can depend on definitions from other -module. Definitions are lazy, and then are resolved only when a a component is requesting it. +module. Definitions are lazy, and then are resolved only when a component is requesting it. Let's take an example, with linked components in separate modules: From 6cdce20ff9bded1df10b9aea1192d550d3b57eac Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:06:02 -0300 Subject: [PATCH 39/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/reference/koin-compose/multiplatform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/multiplatform.md b/docs/reference/koin-compose/multiplatform.md index d6a5f7267..fb141e4d4 100644 --- a/docs/reference/koin-compose/multiplatform.md +++ b/docs/reference/koin-compose/multiplatform.md @@ -6,7 +6,7 @@ This page describe how you can inject your dependencies for your Jetpack & Jetbr ## Starting Koin with Compose - KoinApplication or KoinContext -Most of the time, `startKoin` function is used to start Koin in your application. This is done before running any Composable function. You need to setup Compose with your current Koin instance. Use `KoinContext()` to do so: +Most of the time, `startKoin` function is used to start Koin in your application. This is done before running any Composable function. You need to seting up Compose with your current Koin instance. Use `KoinContext()` to do so: ```kotlin @Composable From 6a5760d2dd6abf67c246d27f70e8484d9c22d891 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:06:26 -0300 Subject: [PATCH 40/77] [DOC][FIX] 'follow up' seems to be a compound adjective before a noun. Use a hyphen: follow-up. --- docs/reference/koin-compose/multiplatform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/multiplatform.md b/docs/reference/koin-compose/multiplatform.md index fb141e4d4..d6c21ee6a 100644 --- a/docs/reference/koin-compose/multiplatform.md +++ b/docs/reference/koin-compose/multiplatform.md @@ -106,7 +106,7 @@ For this use `unloadOnForgotten` or `unloadOnAbandoned` argument for `rememberKo ## Creating Koin Scope with Composable -The composable function `rememberKoinScope` and `KoinScope` allow to handle Koin Scope in a Composable, follow up current to close scope once Composable is ended. +The composable function `rememberKoinScope` and `KoinScope` allow to handle Koin Scope in a Composable, follow-up current to close scope once Composable is ended. :::info this API is still unstable for now From 85dd3f761f58a38108e1be9edbfc89b8cfbaa6b6 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:06:54 -0300 Subject: [PATCH 41/77] [DOC][FIX] The verb 'set up' is spelled as two words. The noun 'setup' is spelled as one. --- docs/reference/koin-android/scope.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index 4d0e81ddb..583abf6a3 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -109,7 +109,7 @@ abstract class ScopeActivity( } ``` -We need to use the `AndroidScopeComponent` interface and implement the `scope` property. This will setup the default scope used by your class. +We need to use the `AndroidScopeComponent` interface and implement the `scope` property. This will setting up the default scope used by your class. ### Android Scope API @@ -132,7 +132,7 @@ class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent { } ``` -We can also setup a retained scope (backed by a ViewModel lifecycle) with the following: +We can also setting up a retained scope (backed by a ViewModel lifecycle) with the following: ```kotlin class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent { From d91b19f328fd51aa0a698deba07ddb35f8e9cd8b Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:07:11 -0300 Subject: [PATCH 42/77] [DOC][FIX] Did you mean: By default,? --- docs/reference/koin-core/scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/scopes.md b/docs/reference/koin-core/scopes.md index e82bc8dde..a4dea5ec2 100644 --- a/docs/reference/koin-core/scopes.md +++ b/docs/reference/koin-core/scopes.md @@ -12,7 +12,7 @@ When the scope context ends, any objects bound under that scope cannot be inject ## Scope definition -By default in Koin, we have 3 kind of scopes: +By default, in Koin, we have 3 kind of scopes: - `single` definition, create an object that persistent with the entire container lifetime (can't be dropped). - `factory` definition, create a new object each time. Short live. No persistence in the container (can't be shared). From 48055b63c22b93305dacd2da2b37c7d04093c244 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:07:51 -0300 Subject: [PATCH 43/77] [DOC][FIX] Did you mean you are, yours are or your? --- docs/reference/koin-core/start-koin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/start-koin.md b/docs/reference/koin-core/start-koin.md index 14ca8b3d0..74f7f003e 100644 --- a/docs/reference/koin-core/start-koin.md +++ b/docs/reference/koin-core/start-koin.md @@ -3,7 +3,7 @@ title: Start Koin --- -Koin is a DSL, a lightweight container and a pragmatic API. Once you have declared your definitions within Koin modules, your are ready to start the Koin container. +Koin is a DSL, a lightweight container and a pragmatic API. Once you have declared your definitions within Koin modules, you are ready to start the Koin container. ### The startKoin function From e4d7d1d91aa911e06a185a07bdc212f65c185140 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:08:14 -0300 Subject: [PATCH 44/77] [DOC][FIX] After 'It', use the third-person verb form needs. --- docs/reference/koin-core/start-koin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-core/start-koin.md b/docs/reference/koin-core/start-koin.md index 74f7f003e..c780ddeb8 100644 --- a/docs/reference/koin-core/start-koin.md +++ b/docs/reference/koin-core/start-koin.md @@ -7,7 +7,7 @@ Koin is a DSL, a lightweight container and a pragmatic API. Once you have declar ### The startKoin function -The `startKoin` function is the main entry point to launch Koin container. It need a *list of Koin modules* to run. +The `startKoin` function is the main entry point to launch Koin container. It needs a *list of Koin modules* to run. Modules are loaded and definitions are ready to be resolved by the Koin container. .Starting Koin From 648926a158f2768925b231d1792b21343e687d69 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:08:33 -0300 Subject: [PATCH 45/77] [DOC][FIX] Did you mean as follows? --- docs/reference/koin-android/start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/start.md b/docs/reference/koin-android/start.md index b86a8cdf3..184efd84b 100644 --- a/docs/reference/koin-android/start.md +++ b/docs/reference/koin-android/start.md @@ -6,7 +6,7 @@ The `koin-android` project is dedicated to provide Koin powers to Android world. ## From your Application class -From your `Application` class you can use the `startKoin` function and inject the Android context with `androidContext` as follow: +From your `Application` class you can use the `startKoin` function and inject the Android context with `androidContext` as follows: ```kotlin class MainApplication : Application() { From eb7e9e1ffd90838db52cd390013889947ce2ab08 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:08:48 -0300 Subject: [PATCH 46/77] [DOC][FIX] After the auxiliary verb 'do', use the base form of a verb. Did you mean suit? --- docs/reference/koin-android/start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/start.md b/docs/reference/koin-android/start.md index 184efd84b..d55ad1ffb 100644 --- a/docs/reference/koin-android/start.md +++ b/docs/reference/koin-android/start.md @@ -51,7 +51,7 @@ From your Koin configuration (in `startKoin { }` block code), you can also confi Within your `KoinApplication` instance, we have an extension `androidLogger` which use the `AndroidLogger()`# This logger is an Android implementation of the Koin logger. -Up to you to change this logger if it doesn't suits to your needs. +Up to you to change this logger if it doesn't suit to your needs. ```kotlin startKoin { From 35114235ffd91d0fd6a09b955a94e5b50578a662 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:09:05 -0300 Subject: [PATCH 47/77] [DOC][FIX] Did you mean want? --- docs/reference/koin-test/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-test/testing.md b/docs/reference/koin-test/testing.md index 52618c5f0..6d2d36a6e 100644 --- a/docs/reference/koin-test/testing.md +++ b/docs/reference/koin-test/testing.md @@ -123,7 +123,7 @@ class MyTest : KoinTest { ``` :::note - declareMock can specify if you want a single or factory, and if you wan to have it in a module path. + declareMock can specify if you want a single or factory, and if you want to have it in a module path. ::: ## Declaring a component on the fly From dd5067df7467ad2bfc60d36dd0bcf308866f319c Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:09:24 -0300 Subject: [PATCH 48/77] [DOC][FIX] The verb 'helps' is used with an infinitive. --- docs/reference/koin-android/viewmodel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/viewmodel.md b/docs/reference/koin-android/viewmodel.md index 72a246ce9..358b5d32f 100644 --- a/docs/reference/koin-android/viewmodel.md +++ b/docs/reference/koin-android/viewmodel.md @@ -21,7 +21,7 @@ Your declared component must at least extends the `android.arch.lifecycle.ViewMo and use the `get()` function to inject dependencies. :::info -The `viewModel`/`viewModelOf` keyword helps declaring a factory instance of ViewModel. This instance will be handled by internal ViewModelFactory and reattach ViewModel instance if needed. +The `viewModel`/`viewModelOf` keyword helps to declare a factory instance of ViewModel. This instance will be handled by internal ViewModelFactory and reattach ViewModel instance if needed. It also will let inject parameters. ::: From 7fdcdbbd6190fbe88dc6fac9d9ad11dccdf30c13 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:09:41 -0300 Subject: [PATCH 49/77] [DOC][FIX] Use an instead of 'a' if the following word starts with a vowel sound, e.g. 'an article', 'an hour'. --- docs/setup/why.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/why.md b/docs/setup/why.md index 3134d13ca..2a2ec43dc 100644 --- a/docs/setup/why.md +++ b/docs/setup/why.md @@ -2,7 +2,7 @@ title: Why Koin? --- -Koin provides a easy and efficient way to incorporate dependency injection into any Kotlin application(Multiplatform, Android, backend ...) +Koin provides an easy and efficient way to incorporate dependency injection into any Kotlin application(Multiplatform, Android, backend ...) The goals of Koin are: - Simplify your Dependency Injection infrastructure with smart API From 80eec7392b31bfd58576ac493ae086dcae117cbc Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:10:00 -0300 Subject: [PATCH 50/77] [DOC][FIX] A comma may be missing after the conjunctive/linking adverb 'However'. --- docs/reference/koin-android/workmanager.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/workmanager.md b/docs/reference/koin-android/workmanager.md index 50acbb03f..eecf8a9d9 100644 --- a/docs/reference/koin-android/workmanager.md +++ b/docs/reference/koin-android/workmanager.md @@ -84,7 +84,7 @@ In case both Koin and workFactory1 provided WorkManagerFactory can instantiate a ## A few assumptions ### Add manifest changes in koin lib itself -We can make it one step less for application developers if koin-androidx-workmanager's own manifest disables the default work manager. However it can be confusing since if the app developer don't initialize koin's work manager infrastructure, he'll end up having no usable work manager factories. +We can make it one step less for application developers if koin-androidx-workmanager's own manifest disables the default work manager. However, it can be confusing since if the app developer don't initialize koin's work manager infrastructure, he'll end up having no usable work manager factories. That's something that checkModules could help: if any class in the project implements ListenableWorker we inspect both manifest and code and make sure they make sense? From 3d1ed429c24c2c3b04792ea4054f44b0d07cdec6 Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:10:30 -0300 Subject: [PATCH 51/77] [DOC][FIX] The progressive form of the verb may be more appropriate here. --- docs/reference/koin-test/checkmodules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-test/checkmodules.md b/docs/reference/koin-test/checkmodules.md index ddd43a5fe..ad3ea4023 100644 --- a/docs/reference/koin-test/checkmodules.md +++ b/docs/reference/koin-test/checkmodules.md @@ -3,7 +3,7 @@ title: Verifying your Koin configuration --- :::note -Koin allows you to verify your configuration modules, avoiding to discover dependency injection issues at runtime. +Koin allows you to verify your configuration modules, avoiding discovering dependency injection issues at runtime. ::: From e67f842672ba68f89575f78163b07a59b05d0b5b Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:11:28 -0300 Subject: [PATCH 52/77] [DOC][FIX] Modal verbs like 'can' or 'will' require the following verb to be in its base form. --- docs/reference/koin-android/scope.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index 583abf6a3..2cfe3c6bb 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -132,7 +132,7 @@ class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent { } ``` -We can also setting up a retained scope (backed by a ViewModel lifecycle) with the following: +We can also to setting up a retained scope (backed by a ViewModel lifecycle) with the following: ```kotlin class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent { From f3529d5c7ab6a08dc6bd882bb718ef30532ed3be Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:12:02 -0300 Subject: [PATCH 53/77] [DOC][FIX] Possible spelling mistake found. --- docs/reference/koin-android/viewmodel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/koin-android/viewmodel.md b/docs/reference/koin-android/viewmodel.md index 358b5d32f..931bbd9f7 100644 --- a/docs/reference/koin-android/viewmodel.md +++ b/docs/reference/koin-android/viewmodel.md @@ -165,7 +165,7 @@ All `stateViewModel` functions are deprecated. You can just use the regular `vie ## Navigation Graph ViewModel -You can scope a ViewModel instance to your Navigation graph. Just retrieve with `by koinNavGraphViewModel()`. You just need your graph Id. +You can scope a ViewModel instance to your Navigation graph. Just retrieve with `by koinNavGraphViewModel()`. You just need your graph id. ```kotlin class NavFragment : Fragment() { From 1e501c4978aa1a26855c9420817988a9f3af83de Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:15:39 -0300 Subject: [PATCH 54/77] [DOC][FIX] Fix library version --- docs/setup/koin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 5bea31204..f1d21c220 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -45,7 +45,7 @@ koin-bom = "x.x.x" ... [libraries] -koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "di-koin" } +koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" } koin-core = { module = "io.insert-koin:koin-core" } ... ``` From c004609b248815f7dd325d5ac9a234964d225f1a Mon Sep 17 00:00:00 2001 From: pedrofsn Date: Sat, 24 Feb 2024 23:26:22 -0300 Subject: [PATCH 55/77] [DOC][FIX] Solves #1709, #1728, #1748, #1737 and #1749. --- docs/reference/koin-android/get-instances.md | 6 +++--- docs/reference/koin-android/modules-android.md | 4 ++-- docs/reference/koin-android/start.md | 10 ++++------ docs/reference/koin-core/modules.md | 8 ++++---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/docs/reference/koin-android/get-instances.md b/docs/reference/koin-android/get-instances.md index e5f530806..dc132a7c2 100644 --- a/docs/reference/koin-android/get-instances.md +++ b/docs/reference/koin-android/get-instances.md @@ -48,12 +48,12 @@ override fun onCreate(savedInstanceState: Bundle?) { ``` :::info -if you class doesn't have extensions, just add KoinComponent interface If you need to `inject()` or `get()` an instance from another class. +if your class doesn't have extensions, just implement the `KoinComponent` interface in it to `inject()` or `get()` an instance from another class. ::: ## Using the Android Context in a Definition -Once your `Application` class you can use `androidContext` function: +Once your `Application` class configures Koin you can use the `androidContext` function to inject Android Context so that it can be resolved later when you need it in modules: ```kotlin class MainApplication : Application() { @@ -62,7 +62,7 @@ class MainApplication : Application() { super.onCreate() startKoin { - //inject Android context + // inject Android context androidContext(this@MainApplication) // ... } diff --git a/docs/reference/koin-android/modules-android.md b/docs/reference/koin-android/modules-android.md index c5aeba0f8..4fda60bc6 100644 --- a/docs/reference/koin-android/modules-android.md +++ b/docs/reference/koin-android/modules-android.md @@ -6,8 +6,8 @@ By using Koin, you describe definitions in modules. In this section we will see ## Using several modules -Components doesn't have to be necessarily in the same module. A module is a logical space to help you organize your definitions, and can depend on definitions from other -module. Definitions are lazy, and then are resolved only when a component is requesting it. +Components don't have to be necessarily in the same module. A module is a logical space to help you organize your definitions, and can depend on definitions from another +module. Definitions are lazy, and they are resolved only when a component requests them. Let's take an example, with linked components in separate modules: diff --git a/docs/reference/koin-android/start.md b/docs/reference/koin-android/start.md index d55ad1ffb..e108ddacc 100644 --- a/docs/reference/koin-android/start.md +++ b/docs/reference/koin-android/start.md @@ -2,7 +2,7 @@ title: Start Koin on Android --- -The `koin-android` project is dedicated to provide Koin powers to Android world. See the [Android setup](../../setup/v3.2#android) section for more details. +The `koin-android` project is dedicated to provide Koin powers to Android world. See the [Android setup](../../setup/koin#android) section for more details. ## From your Application class @@ -22,13 +22,12 @@ class MainApplication : Application() { // Load modules modules(myAppModules) } - } } ``` :::info -You can also start Koin from anywhere if you don't ant to start it from your Application class. +You can also start Koin from anywhere if you don't want to start it from your Application class. ::: If you need to start Koin from another Android class, you can use the `startKoin` function and provide your Android `Context` @@ -48,7 +47,7 @@ From your Koin configuration (in `startKoin { }` block code), you can also confi ### Koin Logging for Android -Within your `KoinApplication` instance, we have an extension `androidLogger` which use the `AndroidLogger()`# +Within your `KoinApplication` instance, we have an extension `androidLogger` which uses the `AndroidLogger()` class. This logger is an Android implementation of the Koin logger. Up to you to change this logger if it doesn't suit to your needs. @@ -69,8 +68,7 @@ You can use Koin properties in the `assets/koin.properties` file, to store keys/ startKoin { // ... // use properties from assets/koin.properties - androidFileProperties() - + androidFileProperties() } ``` diff --git a/docs/reference/koin-core/modules.md b/docs/reference/koin-core/modules.md index dfb661456..48120c1c7 100644 --- a/docs/reference/koin-core/modules.md +++ b/docs/reference/koin-core/modules.md @@ -95,7 +95,7 @@ fun sharedModule() = module { } ``` -This way, your share the definitions and avoid preallocate factories in a value. +This way, you share the definitions and avoid preallocating factories in a value. ## Overriding definition or module (before 3.1.0) @@ -253,12 +253,12 @@ startKoin { modules(featureModule1, featureModule2) } Notice that all modules will be included only once: `dataModule`, `domainModule`, `featureModule1`, `featureModule2`. :::info - If you have any compiling issue while including modules from the same file, either use `get()` Kotlin attribute operator on your module either separate each module in files. See https://github.com/InsertKoinIO/koin/issues/1341 workaround + If you have any compiling issue while including modules from the same file, either use `get()` Kotlin attribute operator on your module or separate each module in files. See https://github.com/InsertKoinIO/koin/issues/1341 workaround ::: ## Lazy modules & background modules loading with Kotlin coroutines [Experimental] -You can now declare "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. +You can now declare a "lazy" Koin module, to avoid triggering any pre allocation of resources and load them in background with Koin start. - `lazyModule` - declare a Lazy Kotlin version of Koin Module - `Module.includes` - allow to include lazy Modules @@ -294,4 +294,4 @@ koin.waitAllStartJobs() koin.runOnKoinStarted { koin -> // run after background load complete } -``` \ No newline at end of file +``` From 69d4c311b4705d3bc01fb5d1b3a8f688f0bcef99 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 11:27:43 +0100 Subject: [PATCH 56/77] Fix back koin-compose version --- projects/compose/koin-compose/build.gradle.kts | 3 +++ projects/gradle.properties | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/projects/compose/koin-compose/build.gradle.kts b/projects/compose/koin-compose/build.gradle.kts index 89e28c795..ac0ac584b 100644 --- a/projects/compose/koin-compose/build.gradle.kts +++ b/projects/compose/koin-compose/build.gradle.kts @@ -5,6 +5,9 @@ plugins { alias(libs.plugins.compose) } +val koinComposeVersion: String by project +version = koinComposeVersion + kotlin { jvm { withJava() diff --git a/projects/gradle.properties b/projects/gradle.properties index 94ebe34d5..c754d2c3b 100644 --- a/projects/gradle.properties +++ b/projects/gradle.properties @@ -6,8 +6,11 @@ org.gradle.parallel=true #Kotlin kotlin.code.style=official + #Koin -koinVersion=3.6.0-alpha1 +koinVersion=3.5.4-rc-1 +koinComposeVersion=1.1.3-rc-1 + #Compose composeCompiler=1.5.7 #Android From 0e5bc325cbc7f7c33de8622085eb1768fcf73753 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 15:51:24 +0100 Subject: [PATCH 57/77] Update Koin extension + Coroutine engine subscription / allow to pass a default CoroutineDispatcher --- .../org/koin/core/KoinApplicationLazyExt.kt | 13 ++++++------ .../core/coroutine/KoinCoroutinesEngine.kt | 21 +++++++++++++------ .../core/extension/KoinCoroutinesExtension.kt | 5 +++-- .../koin/core/extension/ExtensionManager.kt | 2 +- .../org/koin/core/extension/KoinExtension.kt | 4 ++-- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/KoinApplicationLazyExt.kt b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/KoinApplicationLazyExt.kt index c5eaa748a..857b97083 100644 --- a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/KoinApplicationLazyExt.kt +++ b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/KoinApplicationLazyExt.kt @@ -17,6 +17,7 @@ package org.koin.core +import kotlinx.coroutines.CoroutineDispatcher import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.annotation.KoinInternalApi import org.koin.core.extension.coroutinesEngine @@ -35,10 +36,10 @@ import org.koin.core.module.Module * run coroutinesEngine() to setup if needed */ @KoinExperimentalAPI -fun KoinApplication.lazyModules(vararg list: Lazy) { - coroutinesEngine() +fun KoinApplication.lazyModules(vararg moduleList: Lazy,dispatcher: CoroutineDispatcher? = null) { + coroutinesEngine(dispatcher) koin.coroutinesEngine.launchStartJob { - modules(list.map { it.value }) + modules(moduleList.map { it.value }) } } @@ -51,9 +52,9 @@ fun KoinApplication.lazyModules(vararg list: Lazy) { * run coroutinesEngine() to setup if needed */ @KoinExperimentalAPI -fun KoinApplication.lazyModules(list: List>) { - coroutinesEngine() +fun KoinApplication.lazyModules(moduleList: List>,dispatcher: CoroutineDispatcher? = null) { + coroutinesEngine(dispatcher) koin.coroutinesEngine.launchStartJob { - modules(list.map { it.value }) + modules(moduleList.map { it.value }) } } diff --git a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/coroutine/KoinCoroutinesEngine.kt b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/coroutine/KoinCoroutinesEngine.kt index 8ecfcd3b0..3dd236010 100644 --- a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/coroutine/KoinCoroutinesEngine.kt +++ b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/coroutine/KoinCoroutinesEngine.kt @@ -20,6 +20,7 @@ import org.koin.core.Koin import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.annotation.KoinInternalApi import org.koin.core.extension.KoinExtension +import org.koin.core.logger.Logger import org.koin.mp.KoinPlatformCoroutinesTools import kotlin.coroutines.CoroutineContext @@ -28,35 +29,43 @@ import kotlin.coroutines.CoroutineContext * * Help handle coroutines jobs for different purposes * - * @author Arnaud Giulani + * @author Arnaud Giuliani */ @KoinExperimentalAPI @KoinInternalApi -class KoinCoroutinesEngine : CoroutineScope, KoinExtension { - private val dispatcher: CoroutineDispatcher = KoinPlatformCoroutinesTools.defaultCoroutineDispatcher() +class KoinCoroutinesEngine(coroutineDispatcher: CoroutineDispatcher? = null) : CoroutineScope, KoinExtension { + private val dispatcher: CoroutineDispatcher = coroutineDispatcher ?: KoinPlatformCoroutinesTools.defaultCoroutineDispatcher() private val supervisorJob = SupervisorJob() override val coroutineContext: CoroutineContext = supervisorJob + dispatcher internal val startJobs = arrayListOf>() - override lateinit var koin: Koin + private var _koin: Koin? = null + private fun getKoin() : Koin = _koin ?: error("No Koin instance is registered for plugin $this") + private fun getLogger() : Logger = getKoin().logger + + override fun onRegister(koin: Koin) { + _koin = koin + koin.logger.debug("$TAG - init ($dispatcher)") + } fun launchStartJob(block: suspend CoroutineScope.() -> T) { startJobs.add(async { block() }) } suspend fun awaitAllStartJobs() { - koin.logger.debug("await All Start Jobs ...") + getLogger().debug("$TAG - await All Start Jobs ...") startJobs.map { it.await() } startJobs.clear() } override fun onClose() { - koin.logger.debug("onClose $this") + getLogger().debug("$TAG - onClose $this") cancel("KoinCoroutinesEngine shutdown") } companion object { + const val TAG = "[CoroutinesEngine]" const val EXTENSION_NAME = "coroutine-engine" } } diff --git a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/extension/KoinCoroutinesExtension.kt b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/extension/KoinCoroutinesExtension.kt index c141e39c9..9c14b5484 100644 --- a/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/extension/KoinCoroutinesExtension.kt +++ b/projects/core/koin-core-coroutines/src/commonMain/kotlin/org/koin/core/extension/KoinCoroutinesExtension.kt @@ -15,6 +15,7 @@ */ package org.koin.core.extension +import kotlinx.coroutines.CoroutineDispatcher import org.koin.core.Koin import org.koin.core.KoinApplication import org.koin.core.annotation.KoinExperimentalAPI @@ -31,10 +32,10 @@ import org.koin.core.coroutine.KoinCoroutinesEngine.Companion.EXTENSION_NAME */ @OptIn(KoinInternalApi::class) @KoinExperimentalAPI -fun KoinApplication.coroutinesEngine() { +fun KoinApplication.coroutinesEngine(dispatcher : CoroutineDispatcher? = null) { with(koin.extensionManager) { if (getExtensionOrNull(EXTENSION_NAME) == null) { - registerExtension(EXTENSION_NAME, KoinCoroutinesEngine()) + registerExtension(EXTENSION_NAME, KoinCoroutinesEngine(dispatcher)) } } } diff --git a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/ExtensionManager.kt b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/ExtensionManager.kt index 9940eb1c6..e625952bd 100644 --- a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/ExtensionManager.kt +++ b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/ExtensionManager.kt @@ -37,7 +37,7 @@ class ExtensionManager(internal val _koin: Koin) { fun registerExtension(id: String, extension: T) { extensions[id] = extension - extension.koin = _koin + extension.onRegister(_koin) } fun close() { diff --git a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/KoinExtension.kt b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/KoinExtension.kt index dfb853137..a2e5dc923 100644 --- a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/KoinExtension.kt +++ b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/extension/KoinExtension.kt @@ -25,9 +25,9 @@ import org.koin.core.Koin interface KoinExtension { /** - * Current Koin instance + * register from Koin instance */ - var koin: Koin + fun onRegister(koin : Koin) /** * Called when closing Koin From d357d7fd6a58c2cef5311339c165b68205488189 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 15:51:43 +0100 Subject: [PATCH 58/77] Fall back to Dispatchers.Default as default dispatcher and not IO --- .../jvmMain/kotlin/org/koin/mp/KoinPlatformCoroutinesTools.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/core/koin-core-coroutines/src/jvmMain/kotlin/org/koin/mp/KoinPlatformCoroutinesTools.kt b/projects/core/koin-core-coroutines/src/jvmMain/kotlin/org/koin/mp/KoinPlatformCoroutinesTools.kt index 88e75296b..f1740bf54 100644 --- a/projects/core/koin-core-coroutines/src/jvmMain/kotlin/org/koin/mp/KoinPlatformCoroutinesTools.kt +++ b/projects/core/koin-core-coroutines/src/jvmMain/kotlin/org/koin/mp/KoinPlatformCoroutinesTools.kt @@ -21,5 +21,5 @@ import org.koin.core.annotation.KoinExperimentalAPI @KoinExperimentalAPI actual object KoinPlatformCoroutinesTools { - actual fun defaultCoroutineDispatcher(): CoroutineDispatcher = Dispatchers.IO + actual fun defaultCoroutineDispatcher(): CoroutineDispatcher = Dispatchers.Default } From ffea92fa7a6a00b80cc2ec3260044e3d6383b454 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 15:51:50 +0100 Subject: [PATCH 59/77] Test update --- .../kotlin/org/koin/test/LazyModuleTest.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/projects/core/koin-core-coroutines/src/jvmTest/kotlin/org/koin/test/LazyModuleTest.kt b/projects/core/koin-core-coroutines/src/jvmTest/kotlin/org/koin/test/LazyModuleTest.kt index a71087c56..9226c26f0 100644 --- a/projects/core/koin-core-coroutines/src/jvmTest/kotlin/org/koin/test/LazyModuleTest.kt +++ b/projects/core/koin-core-coroutines/src/jvmTest/kotlin/org/koin/test/LazyModuleTest.kt @@ -1,5 +1,6 @@ package org.koin.test +import kotlinx.coroutines.Dispatchers import org.koin.core.lazyModules import org.koin.core.logger.Level import org.koin.core.module.dsl.bind @@ -39,4 +40,26 @@ class LazyModuleTest { assertNotNull(koin.getOrNull()) } + + @Test + fun test_dispatchers() { + var resolved: Boolean? = null + val m2 = lazyModule { + resolved = true + singleOf(::ClassB) + } + val m1 = lazyModule { + includes(m2) + singleOf(::ClassA) { bind() } + } + assertTrue(resolved == null, "resolved should be null: $resolved") + + val koin = koinApplication { + printLogger(Level.DEBUG) + lazyModules(m1, dispatcher = Dispatchers.IO) + }.koin + koin.waitAllStartJobs() + + assertNotNull(koin.getOrNull()) + } } From 9c5426d6c6fadaf574bd993c91f2740980eb3cb2 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 16:31:21 +0100 Subject: [PATCH 60/77] update doc --- docs/reference/koin-core/lazy-modules.md | 66 ++++++++++++++++++++++++ docs/reference/koin-core/modules.md | 40 -------------- 2 files changed, 66 insertions(+), 40 deletions(-) create mode 100644 docs/reference/koin-core/lazy-modules.md diff --git a/docs/reference/koin-core/lazy-modules.md b/docs/reference/koin-core/lazy-modules.md new file mode 100644 index 000000000..e7e945112 --- /dev/null +++ b/docs/reference/koin-core/lazy-modules.md @@ -0,0 +1,66 @@ +--- +title: Lazy Modules and Background Loading +--- + +In this section we will see how to organize your modules with lazy loading approach. + +## Defining Lazy Modules [Experimental] + +You can now declare lazy Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. + +- `lazyModule` - declare a Lazy Kotlin version of Koin Module +- `Module.includes` - allow to include lazy Modules + +A good example is always better to understand: + +```kotlin +// Some lazy modules +val m2 = lazyModule { + singleOf(::ClassB) +} + +// include m2 lazy module +val m1 = lazyModule { + includes(m2) + singleOf(::ClassA) { bind() } +} +``` + +:::info + LazyModule won't trigger any resources until it has been loaded by the following API +::: + +## Background loading with Kotlin coroutines [Experimental] + +Once you have declared some lazy modules, you can load them in background from your Koin configuration and further more. + +- `KoinApplication.lazyModules` - load lazy modules in background with coroutines, regarding platform default Dispatchers +- `Koin.waitAllStartJobs` - wait for start jobs to complete +- `Koin.runOnKoinStarted` - run block code after start completion + +A good example is always better to understand: + +```kotlin +startKoin { + // load lazy Modules in background + lazyModules(m1) +} + +val koin = KoinPlatform.getKoin() + +// wait for loading jobs to finish +koin.waitAllStartJobs() + +// or run code after loading is done +koin.runOnKoinStarted { koin -> + // run after background load complete +} +``` + +:::note + The `lazyModules` function allow you to specify a dispatcher: `lazyModules(modules, dispatcher = Dispatcher.IO)` +::: + +:::info + Default dispatcher for coroutines engine is `Dispatchers.Default` +::: \ No newline at end of file diff --git a/docs/reference/koin-core/modules.md b/docs/reference/koin-core/modules.md index c84c5081d..62566ce06 100644 --- a/docs/reference/koin-core/modules.md +++ b/docs/reference/koin-core/modules.md @@ -255,43 +255,3 @@ Notice that all modules will be included only once: `dataModule`, `domainModule` :::info If you have any compiling issue while including modules from the same file, either use `get()` Kotlin attribute operator on your module either separate each module in files. See https://github.com/InsertKoinIO/koin/issues/1341 workaround ::: - -## Lazy modules & background modules loading with Kotlin coroutines [Experimental] - -You can now declare "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. - -- `lazyModule` - declare a Lazy Kotlin version of Koin Module -- `Module.includes` - allow to include lazy Modules -- `KoinApplication.lazyModules` - load lazy modules in background with coroutines, regarding platform default Dispatchers -- `Koin.waitAllStartJobs` - wait for start jobs to complete -- `Koin.runOnKoinStarted` - run block code after start completion - -A good example is always better to understand: - -```kotlin -// Some lazy modules -val m2 = lazyModule { - singleOf(::ClassB) -} - -// include m2 lazy module -val m1 = lazyModule { - includes(m2) - singleOf(::ClassA) { bind() } -} - -startKoin { - // load lazy Modules in background - lazyModules(m1) -} - -val koin = KoinPlatform.getKoin() - -// wait for loading jobs to finish -koin.waitAllStartJobs() - -// or run code after loading is done -koin.runOnKoinStarted { koin -> - // run after background load complete -} -``` \ No newline at end of file From 8d0209fe9d17af3a95a237647f3067dc7f8905d3 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Thu, 29 Feb 2024 19:04:52 +0100 Subject: [PATCH 61/77] Use stately collections for safe collection on native side - Fix #1765 #1711 --- projects/core/koin-core/build.gradle.kts | 1 + .../commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt | 2 +- .../koin-core/src/jsMain/kotlin/org/koin/mp/PlatformTools.kt | 3 ++- .../src/nativeMain/kotlin/org/koin/mp/KoinPlatformTools.kt | 3 ++- projects/gradle/libs.versions.toml | 2 ++ 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/projects/core/koin-core/build.gradle.kts b/projects/core/koin-core/build.gradle.kts index 4baf6e50a..c87aa0594 100644 --- a/projects/core/koin-core/build.gradle.kts +++ b/projects/core/koin-core/build.gradle.kts @@ -34,6 +34,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.extras.stately) + implementation(libs.extras.stately.collections) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt index 7e91adb69..95034e020 100644 --- a/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt +++ b/projects/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt @@ -89,7 +89,7 @@ class ScopeRegistry(private val _koin: Koin) { } private fun closeAllScopes() { - _scopes.values.forEach { scope -> + _scopes.values.toList().forEach { scope -> scope.close() } } diff --git a/projects/core/koin-core/src/jsMain/kotlin/org/koin/mp/PlatformTools.kt b/projects/core/koin-core/src/jsMain/kotlin/org/koin/mp/PlatformTools.kt index 3612f0a69..ace661ba3 100644 --- a/projects/core/koin-core/src/jsMain/kotlin/org/koin/mp/PlatformTools.kt +++ b/projects/core/koin-core/src/jsMain/kotlin/org/koin/mp/PlatformTools.kt @@ -16,6 +16,7 @@ package org.koin.mp +import co.touchlab.stately.collections.ConcurrentMutableMap import co.touchlab.stately.concurrency.ThreadLocalRef import org.koin.core.context.GlobalContext import org.koin.core.context.KoinContext @@ -51,7 +52,7 @@ actual object KoinPlatformTools { actual fun defaultLogger(level: Level): Logger = PrintLogger(level) actual fun defaultContext(): KoinContext = GlobalContext actual fun synchronized(lock: Lockable, block: () -> R) = block() - actual fun safeHashMap(): MutableMap = HashMap() + actual fun safeHashMap(): MutableMap = ConcurrentMutableMap() } actual typealias Lockable = Any diff --git a/projects/core/koin-core/src/nativeMain/kotlin/org/koin/mp/KoinPlatformTools.kt b/projects/core/koin-core/src/nativeMain/kotlin/org/koin/mp/KoinPlatformTools.kt index 4b92b9a67..e1ba05cf0 100644 --- a/projects/core/koin-core/src/nativeMain/kotlin/org/koin/mp/KoinPlatformTools.kt +++ b/projects/core/koin-core/src/nativeMain/kotlin/org/koin/mp/KoinPlatformTools.kt @@ -1,5 +1,6 @@ package org.koin.mp +import co.touchlab.stately.collections.ConcurrentMutableMap import co.touchlab.stately.concurrency.Lock import co.touchlab.stately.concurrency.withLock import co.touchlab.stately.concurrency.ThreadLocalRef @@ -28,7 +29,7 @@ actual object KoinPlatformTools { actual fun synchronized(lock: Lockable, block: () -> R): R = lock.lock.withLock { block() } - actual fun safeHashMap(): MutableMap = HashMap() + actual fun safeHashMap(): MutableMap = ConcurrentMutableMap() } actual open class Lockable { diff --git a/projects/gradle/libs.versions.toml b/projects/gradle/libs.versions.toml index ce120f137..add383832 100644 --- a/projects/gradle/libs.versions.toml +++ b/projects/gradle/libs.versions.toml @@ -36,6 +36,8 @@ slf4j = "1.7.36" # Core kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } extras-stately = { module = "co.touchlab:stately-concurrency", version.ref = "stately" } +extras-stately-collections = { module = "co.touchlab:stately-concurrent-collections", version.ref = "stately" } + # Test kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } test-junit = { module = "junit:junit", version.ref = "junit" } From d58349a395e9a0d02ad4039dc02489e71b2731a2 Mon Sep 17 00:00:00 2001 From: Gustavo Barbosa Date: Thu, 29 Feb 2024 17:02:07 -0300 Subject: [PATCH 62/77] testing the logic to create a ViewModel instance --- .../androidx/viewmodel/GetViewModelTest.kt | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt diff --git a/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt new file mode 100644 index 000000000..e12e7818d --- /dev/null +++ b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt @@ -0,0 +1,141 @@ +package org.koin.test.androidx.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelStore +import androidx.lifecycle.viewmodel.CreationExtras +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.Assert.assertNotNull +import org.junit.Test +import org.koin.androidx.viewmodel.resolveViewModel +import org.koin.core.annotation.KoinInternalApi +import org.koin.core.qualifier.Qualifier +import org.koin.core.scope.Scope + +@KoinInternalApi +class GetViewModelTest { + + private val viewModelStore: ViewModelStore = mockk(relaxed = true) + private val extras: CreationExtras = mockk() + private val qualifier: Qualifier = mockk() + private val scope: Scope = mockk() + + @Test + fun `should return a ViewModel with a default Android key`() { + val classToTest = ViewModel::class + every { scope.isRoot } returns true + + val firstViewModel = resolveViewModel( + classToTest, + viewModelStore, + null, + extras, + null, + scope, + null + ) + + val expectedKey = "$DEFAULT_ANDROID_VIEW_MODEL_KEY:${classToTest.qualifiedName}" + + assertNotNull(firstViewModel) + verify { viewModelStore[expectedKey] } + } + + @Test + fun `should return a ViewModel considering a specific key, qualifier and a non root scope`() { + val classToTest = ViewModel::class + val qualifierName = "qualifier" + val key = "key" + val scopeId = "scopeId" + + every { scope.isRoot } returns false + every { scope.id } returns scopeId + every { qualifier.value } returns qualifierName + + val viewModel = resolveViewModel( + classToTest, + viewModelStore, + key, + extras, + qualifier, + scope, + null + ) + + val koinVmKey = "$qualifierName$key$scopeId" + + assertNotNull(viewModel) + verify { viewModelStore[koinVmKey] } + } + + @Test + fun `should return a ViewModel considering only a non root scope identifier`() { + val classToTest = ViewModel::class + val scopeId = "scopeId" + + every { scope.isRoot } returns false + every { scope.id } returns scopeId + + val viewModel = resolveViewModel( + classToTest, + viewModelStore, + null, + extras, + null, + scope, + null + ) + + assertNotNull(viewModel) + verify { viewModelStore[scopeId] } + } + + @Test + fun `should return a ViewModel considering a key and a root scope identifier`() { + val classToTest = ViewModel::class + val key = "key" + + every { scope.isRoot } returns true + + val viewModel = resolveViewModel( + classToTest, + viewModelStore, + key, + extras, + null, + scope, + null + ) + + assertNotNull(viewModel) + verify { viewModelStore[key] } + } + + @Test + fun `should return a ViewModel considering a qualifier and a root scope identifier`() { + val classToTest = ViewModel::class + val qualifierValue = "qualifier" + + every { scope.isRoot } returns true + every { qualifier.value } returns qualifierValue + + val viewModel = resolveViewModel( + classToTest, + viewModelStore, + null, + extras, + qualifier, + scope, + null + ) + + assertNotNull(viewModel) + verify { viewModelStore[qualifierValue] } + } + + companion object { + const val DEFAULT_ANDROID_VIEW_MODEL_KEY = + "androidx.lifecycle.ViewModelProvider.DefaultKey" + } +} \ No newline at end of file From efd4edbdb5ab111469897492b48fd4acb4deedd9 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Fri, 1 Mar 2024 10:30:11 +0100 Subject: [PATCH 63/77] Update unused test dependencies --- projects/core/koin-test-junit4/build.gradle.kts | 2 +- projects/core/koin-test/build.gradle.kts | 1 - projects/test-macos.sh | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100755 projects/test-macos.sh diff --git a/projects/core/koin-test-junit4/build.gradle.kts b/projects/core/koin-test-junit4/build.gradle.kts index ca5471d44..517a9c50b 100644 --- a/projects/core/koin-test-junit4/build.gradle.kts +++ b/projects/core/koin-test-junit4/build.gradle.kts @@ -7,7 +7,7 @@ plugins { dependencies { api(project(":core:koin-test")) implementation(libs.test.junit) - implementation(libs.kotlin.test) + testImplementation(libs.kotlin.test) testImplementation(libs.test.mockito) } diff --git a/projects/core/koin-test/build.gradle.kts b/projects/core/koin-test/build.gradle.kts index b92e7008b..3801e5dc8 100644 --- a/projects/core/koin-test/build.gradle.kts +++ b/projects/core/koin-test/build.gradle.kts @@ -34,7 +34,6 @@ kotlin { sourceSets { commonMain.dependencies { api(project(":core:koin-core")) - implementation(libs.kotlin.test) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/projects/test-macos.sh b/projects/test-macos.sh new file mode 100755 index 000000000..e5d676bb8 --- /dev/null +++ b/projects/test-macos.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +./gradlew cleanTest :core:koin-core:macosArm64Test --parallel --no-build-cache From ba774f2cfee4bb9eacb4982cf4d0c2ba985a7b47 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Fri, 1 Mar 2024 20:02:48 +0100 Subject: [PATCH 64/77] Add tests + Fix koin-test jvm reflect import --- .../kotlin/org/koin/test/CheckModulesTest.kt | 82 ++++++++++++++++--- .../test/kotlin/org/koin/test/Components.kt | 3 + projects/core/koin-test/build.gradle.kts | 3 + .../org/koin/test/check/CheckModules.kt | 3 + .../org/koin/test/check/CheckModulesDSL.kt | 2 + 5 files changed, 83 insertions(+), 10 deletions(-) diff --git a/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt b/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt index 137d626ac..cc77360e4 100644 --- a/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt +++ b/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/CheckModulesTest.kt @@ -1,15 +1,15 @@ package org.koin.test import org.junit.Assert.fail +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.koin.core.logger.Level +import org.koin.core.module.dsl.createdAtStart +import org.koin.core.module.dsl.withOptions import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named -import org.koin.dsl.bind -import org.koin.dsl.binds -import org.koin.dsl.koinApplication -import org.koin.dsl.module +import org.koin.dsl.* import org.koin.test.check.checkKoinModules import org.koin.test.check.checkModules import org.koin.test.mock.MockProviderRule @@ -17,6 +17,8 @@ import org.mockito.Mockito import java.util.* import kotlin.test.assertEquals import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class CheckModulesTest { @@ -87,6 +89,69 @@ class CheckModulesTest { } } + @Test + fun `check a module - created at start`() { + val modules = module { + single { Simple.ComponentB(get()) } withOptions { createdAtStart() } + } + + koinApplication(createEagerInstances = false) { + modules(modules) + checkModules { + withInstance() + } + } + } + + @Test + fun `check module - dependency and param in one class`() { + val modules = module { + factory { p -> Simple.MyString(p.get()) } + } + + koinApplication { + modules(modules) + checkModules { + withParameter { "test" } + } + } + } + + @Test + fun `check module - dependency and param in one class - 2`() { + val modules = module { + factory { Simple.ComponentA() } + factory { p -> Simple.MyComplexString2(get(), p.get()) } + } + + koinApplication { + printLogger(Level.DEBUG) + modules(modules) + checkModules { +// withInstance() + withParameter { "test" } + } + } + } + + // Not working + @Test + @Ignore + fun `check module - dependency and param in one class - 3`() { + val modules = module { + factory { p -> Simple.MyComplexBool(get(), p.get()) } + } + + koinApplication { + printLogger(Level.DEBUG) + modules(modules) + checkModules { + withInstance() + withParameter { true } + } + } + } + @Test fun `check a scoped module`() { koinApplication { @@ -306,8 +371,8 @@ class CheckModulesTest { printLogger(Level.DEBUG) modules( module { - single { (s: String) -> Simple.MyString(s) } - single(UpperCase) { (s: String) -> Simple.MyString(s.uppercase(Locale.getDefault())) } + single { p -> Simple.MyString(p.get()) } + single(UpperCase) { p -> Simple.MyString(p.get().uppercase(Locale.getDefault())) } }, ) }.checkModules { @@ -589,9 +654,6 @@ class CheckModulesTest { }.checkModules() } - assertEquals( - expected = "instance of class java.lang.String (Kotlin reflection is not available) is not inheritable from int (Kotlin reflection is not available)", - actual = exception.message, - ) + assertNotNull(exception.message) } } diff --git a/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt b/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt index 4ac4843b4..259713684 100644 --- a/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt +++ b/projects/core/koin-test-junit4/src/test/kotlin/org/koin/test/Components.kt @@ -11,6 +11,9 @@ class Simple { class ComponentD() class ComponentE(val d: ComponentD) class MyString(val s: String) + class MyComplexString(val s: String, val a : ComponentA) + class MyComplexString2(val a : ComponentA, val s: String) + class MyComplexBool(val a : ComponentA, val b : Boolean) class UUIDComponent { fun getUUID() = UUID.randomUUID().toString() diff --git a/projects/core/koin-test/build.gradle.kts b/projects/core/koin-test/build.gradle.kts index 3801e5dc8..1e6df8230 100644 --- a/projects/core/koin-test/build.gradle.kts +++ b/projects/core/koin-test/build.gradle.kts @@ -35,6 +35,9 @@ kotlin { commonMain.dependencies { api(project(":core:koin-core")) } + jvmMain.dependencies { + implementation(kotlin("reflect")) + } commonTest.dependencies { implementation(libs.kotlin.test) } diff --git a/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt b/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt index 44a6e4cd1..96eb7c472 100644 --- a/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt +++ b/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModules.kt @@ -35,6 +35,8 @@ import org.koin.mp.KoinPlatformTools import org.koin.test.mock.MockProvider import org.koin.test.parameter.MockParameter +//TODO TO BE DEPRECATED in 3.6 + /** * Check all definition's dependencies - start all modules and check if definitions can run */ @@ -152,6 +154,7 @@ private fun Koin.checkDefinition( ]?.invoke( definition.qualifier, ) ?: MockParameter(scope, allParameters.defaultValues) + logger.info("[Check] definition: $definition") scope.get(definition.primaryType, definition.qualifier) { parameters } diff --git a/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt b/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt index f154ac1af..f41ab1310 100644 --- a/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt +++ b/projects/core/koin-test/src/commonMain/kotlin/org/koin/test/check/CheckModulesDSL.kt @@ -24,6 +24,8 @@ import org.koin.mp.KoinPlatformTools import org.koin.test.mock.MockProvider import kotlin.reflect.KClass +//TODO TO BE DEPRECATED in 3.6 + data class CheckedComponent(val qualifier: Qualifier? = null, val type: KClass<*>) class ParametersBinding(val koin: Koin) { From 32fcda5e5ef434d633797012e4b40c5396cc6121 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 14:48:42 +0100 Subject: [PATCH 65/77] added some tests --- .../kotlin/org/koin/test/Components.kt | 4 ++++ .../src/jvmTest/kotlin/VerifyModulesTest.kt | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/projects/core/koin-test/src/commonTest/kotlin/org/koin/test/Components.kt b/projects/core/koin-test/src/commonTest/kotlin/org/koin/test/Components.kt index 9765356ed..d1a8fe736 100644 --- a/projects/core/koin-test/src/commonTest/kotlin/org/koin/test/Components.kt +++ b/projects/core/koin-test/src/commonTest/kotlin/org/koin/test/Components.kt @@ -18,6 +18,10 @@ class Simple { class CycleAB(val b: CycleBA) class CycleBA(val a: CycleAB) + + class MyComplexBool(val a : ComponentA, val b : Boolean) + + fun buildB(a: ComponentA) : MyComponentB = ComponentB(a) } object UpperCase : Qualifier { diff --git a/projects/core/koin-test/src/jvmTest/kotlin/VerifyModulesTest.kt b/projects/core/koin-test/src/jvmTest/kotlin/VerifyModulesTest.kt index d1acfa89c..74f2b6d7b 100644 --- a/projects/core/koin-test/src/jvmTest/kotlin/VerifyModulesTest.kt +++ b/projects/core/koin-test/src/jvmTest/kotlin/VerifyModulesTest.kt @@ -1,8 +1,12 @@ +import org.koin.core.logger.Level +import org.koin.core.module.dsl.factoryOf import org.koin.core.module.dsl.singleOf import org.koin.core.qualifier.named import org.koin.dsl.bind +import org.koin.dsl.koinApplication import org.koin.dsl.module import org.koin.test.Simple +import org.koin.test.check.checkModules import org.koin.test.verify.CircularInjectionException import org.koin.test.verify.MissingKoinDefinitionException import org.koin.test.verify.Verify @@ -162,4 +166,22 @@ class VerifyModulesTest { System.err.println("$e") } } + + @Test + fun `verify dependency and param in one class - 3`() { + val modules = module { + factory { p -> Simple.MyComplexBool(get(), p.get()) } + } + + modules.verify(extraTypes = listOf(Simple.ComponentA::class, Boolean::class)) + } + + @Test + fun `verify function builder`() { + val modules = module { + factoryOf(Simple::buildB) + } + + modules.verify(extraTypes = listOf(Simple.ComponentA::class)) + } } From 524c46b700cd1cad80be4b87502704c5bd77c3d1 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 15:11:40 +0100 Subject: [PATCH 66/77] add quickstart to allow edition --- docs/quickstart/android-annotations.md | 269 +++++++++++++++++++++++++ docs/quickstart/android-compose.md | 245 ++++++++++++++++++++++ docs/quickstart/android-viewmodel.md | 207 +++++++++++++++++++ docs/quickstart/android.md | 207 +++++++++++++++++++ docs/quickstart/junit-test.md | 93 +++++++++ docs/quickstart/kmm.md | 204 +++++++++++++++++++ docs/quickstart/kotlin-annotations.md | 182 +++++++++++++++++ docs/quickstart/kotlin.md | 165 +++++++++++++++ docs/quickstart/ktor.md | 184 +++++++++++++++++ 9 files changed, 1756 insertions(+) create mode 100755 docs/quickstart/android-annotations.md create mode 100755 docs/quickstart/android-compose.md create mode 100755 docs/quickstart/android-viewmodel.md create mode 100755 docs/quickstart/android.md create mode 100644 docs/quickstart/junit-test.md create mode 100755 docs/quickstart/kmm.md create mode 100755 docs/quickstart/kotlin-annotations.md create mode 100755 docs/quickstart/kotlin.md create mode 100755 docs/quickstart/ktor.md diff --git a/docs/quickstart/android-annotations.md b/docs/quickstart/android-annotations.md new file mode 100755 index 000000000..d4b07c2a8 --- /dev/null +++ b/docs/quickstart/android-annotations.md @@ -0,0 +1,269 @@ +--- +title: Android - Annotations +--- + +> This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. +> You need around __10/15 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/android) +::: + +## Gradle Setup + +Let's configure the KSP Plugin like this: + +```groovy +apply plugin: 'com.google.devtools.ksp' + +android { + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + test.java.srcDirs += 'src/test/kotlin' + } + // For KSP + applicationVariants.configureEach { variant -> + kotlin.sourceSets { + getByName(name) { + kotlin.srcDir("build/generated/ksp/${variant.name}/kotlin") + } + } + } +} +``` + +Add the Koin Android dependency like below: + +```groovy +dependencies { + // Koin + implementation "io.insert-koin:koin-android:$koin_version" + implementation "io.insert-koin:koin-annotations:$koin_ksp_version" + ksp "io.insert-koin:koin-ksp-compiler:$koin_ksp_version" +} +``` + + + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `MainActivity` class with a Presenter or a ViewModel: + +> Users -> UserRepository -> (Presenter or ViewModel) -> MainActivity + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Let's declare a `AppModule` module class like below. + +```kotlin +@Module +@ComponentScan("org.koin.sample") +class AppModule +``` + +* We use the `@Module` to declare our class as Koin module +* The `@ComponentScan("org.koin.sample")` allow to scann any Koin definition in `"org.koin.sample"`package + +Let's simply add `@Single` on `UserRepositoryImpl` class to declare it as singleton: + +```kotlin +@Single +class UserRepositoryImpl : UserRepository { + // ... +} +``` + +## Displaying User with Presenter + +Let's write a presenter component to display a user: + +```kotlin +class UserPresenter(private val repository: UserRepository) { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +We declare `UserPresenter` in our Koin module. We declare it as a `factory` definition with the `@Factory` annotation, to not keep any instance in memory (avoid any leak with Android lifecycle): + +```kotlin +@Factory +class UserPresenter(private val repository: UserRepository) { + // ... +} +``` + +## Injecting Dependencies in Android + +The `UserPresenter` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `by inject()` delegate function: + +```kotlin +class MainActivity : AppCompatActivity() { + + private val presenter: UserPresenter by inject() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //... + } +} +``` + +That's it, your app is ready. + +:::info +The `by inject()` function allows us to retrieve Koin instances, in Android components runtime (Activity, fragment, Service...) +::: + +## Start Koin + +We need to start Koin with our Android application. Just call the `startKoin()` function in the application's main entry point, our `MainApplication` class: + +```kotlin +// generated +import org.koin.ksp.generated.* + +class MainApplication : Application(){ + override fun onCreate() { + super.onCreate() + + startKoin{ + androidLogger() + androidContext(this@MainApplication) + modules(AppModule().module) + } + } +} +``` + +The Koin module is generated from `AppModule` with the `.module` extension: Just use the `AppModule().module` expression to get the Koin module from the annotations. + +:::info +The `import org.koin.ksp.generated.*` import is required to allow to use generated Koin module content +::: + +## Displaying User with ViewModel + +Let's write a ViewModel component to display a user: + +```kotlin +@KoinViewModel +class UserViewModel(private val repository: UserRepository) : ViewModel() { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserViewModel`s constructor + +The `UserViewModel` is tagged with `@KoinViewModel` annotation to declare the Koin ViewModel definition, to not keep any instance in memory (avoid any leak with Android lifecycle). + + +## Injecting ViewModel in Android + +The `UserViewModel` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `by viewModel()` delegate function: + +```kotlin +class MainActivity : AppCompatActivity() { + + private val viewModel: UserViewModel by viewModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //... + } +} +``` + +## Compile Time Checks + +Koin Annotations allows to check your Koin configuration at compile time. This is available by jusing the following Gradle option: + +```groovy +ksp { + arg("KOIN_CONFIG_CHECK","true") +} +``` + +## Verifying your App! + +We can ensure that our Koin configuration is good before launching our app, by verifying our Koin configuration with a simple JUnit Test. + +### Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +// Add Maven Central to your repositories if needed +repositories { + mavenCentral() +} + +dependencies { + + // Koin for Tests + testImplementation "io.insert-koin:koin-test-junit4:$koin_version" +} +``` + +### Checking your modules + +The `verify()` function allow to verify the given Koin modules: + +```kotlin +class CheckModulesTest : KoinTest { + + @Test + fun checkAllModules() { + + AppModule().module.verify( + extraTypes = listOf( + SavedStateHandle::class + )) + } +} +``` + +With just a JUnit test, you can ensure your definitions configuration are not missing anything! diff --git a/docs/quickstart/android-compose.md b/docs/quickstart/android-compose.md new file mode 100755 index 000000000..e7ef99510 --- /dev/null +++ b/docs/quickstart/android-compose.md @@ -0,0 +1,245 @@ +--- +title: Android - Jetpack Compose +--- + +> This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. +> You need around __10 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/android-compose) +::: + +## Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +dependencies { + + // Koin for Android + implementation "io.insert-koin:koin-androidx-compose:$koin_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `MainActivity` class with a Presenter or a ViewModel: + +> Users -> UserRepository -> (Presenter or ViewModel) -> Composable + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +```kotlin +val appModule = module { + +} +``` + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } +} +``` + +## Displaying User with UserViewModel + +### The `UserViewModel` class + +Let's write a ViewModel component to display a user: + +```kotlin +class UserViewModel(private val repository: UserRepository) : ViewModel() { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserViewModel's constructor + +We declare `UserViewModel` in our Koin module. We declare it as a `viewModel` definition, to not keep any instance in memory (avoid any leak with Android lifecycle): + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + viewModel { MyViewModel(get()) } +} +``` + +> The `get()` function allow to ask Koin to resolve the needed dependency. + +### Injecting ViewModel in Compose + +The `UserViewModel` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `koinViewModel()` function: + +```kotlin +@Composable +fun ViewModelInject(userName : String, viewModel: UserViewModel = koinViewModel()){ + Text(text = viewModel.sayHello(userName), modifier = Modifier.padding(8.dp)) +} +``` + +:::info +The `koinViewModel` function allows us to retrieve a ViewModel instances, create the associated ViewModel Factory for you and bind it to the lifecycle +::: + +## Displaying User with UserStateHolder + +### The `UserStateHolder` class + +Let's write a ViewModel component to display a user: + +```kotlin +class UserStateHolder(private val repository: UserRepository) { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserViewModel's constructor + +We declare `UserViewModel` in our Koin module. We declare it as a `viewModel` definition, to not keep any instance in memory (avoid any leak with Android lifecycle): + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + factory { UserStateHolder(get()) } +} +``` + +### Injecting UserStateHolder in Compose + +The `UserViewModel` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `get()` function: + +```kotlin +@Composable +fun FactoryInject(userName : String, presenter: UserStateHolder = get()){ + Text(text = presenter.sayHello(userName), modifier = Modifier.padding(8.dp)) +} +``` + +:::info +The `get` function allows us to retrieve a ViewModel instances, create the associated ViewModel Factory for you and bind it to the lifecycle +::: + + +## Start Koin + +We need to start Koin with our Android application. Just call the `startKoin()` function in the application's main entry point, our `MainApplication` class: + +```kotlin +class MainApplication : Application(){ + override fun onCreate() { + super.onCreate() + + startKoin{ + androidLogger() + androidContext(this@MainApplication) + modules(appModule) + } + } +} +``` + +:::info +The `modules()` function in `startKoin` load the given list of modules +::: + +## Koin module: classic or constructor DSL? + +Here is the Koin moduel declaration for our app: + +```kotlin +val appModule = module { + single { HelloRepositoryImpl() } + viewModel { MyViewModel(get()) } +} +``` + +We can write it in a more compact way, by using constructors: + +```kotlin +val appModule = module { + singleOf(::UserRepositoryImpl) { bind() } + viewModelOf(::UserViewModel) +} +``` + +## Verifying your App! + +We can ensure that our Koin configuration is good before launching our app, by verifying our Koin configuration with a simple JUnit Test. + +### Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +// Add Maven Central to your repositories if needed +repositories { + mavenCentral() +} + +dependencies { + + // Koin for Tests + testImplementation "io.insert-koin:koin-test-junit4:$koin_version" +} +``` + +### Checking your modules + +The `verify()` function allow to verify the given Koin modules: + +```kotlin +class CheckModulesTest : KoinTest { + + @Test + fun checkAllModules() { + appModule.verify() + } +} +``` + +With just a JUnit test, you can ensure your definitions configuration are not missing anything! + diff --git a/docs/quickstart/android-viewmodel.md b/docs/quickstart/android-viewmodel.md new file mode 100755 index 000000000..5f6b5d52a --- /dev/null +++ b/docs/quickstart/android-viewmodel.md @@ -0,0 +1,207 @@ +--- +title: Android - ViewModel +--- + +> This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. +> You need around __10/15 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/android) +::: + +## Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +dependencies { + + // Koin for Android + implementation "io.insert-koin:koin-android:$koin_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `MainActivity` class with a Presenter or a ViewModel: + +> Users -> UserRepository -> (Presenter or ViewModel) -> MainActivity + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +```kotlin +val appModule = module { + +} +``` + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } +} +``` + +## Displaying User with ViewModel + +Let's write a ViewModel component to display a user: + +```kotlin +class UserViewModel(private val repository: UserRepository) : ViewModel() { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserViewModel`s constructor + +We declare `UserViewModel` in our Koin module. We declare it as a `viewModel` definition, to not keep any instance in memory (avoid any leak with Android lifecycle): + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + viewModel { MyViewModel(get()) } +} +``` + +> The `get()` function allow to ask Koin to resolve the needed dependency. + +## Injecting ViewModel in Android + +The `UserViewModel` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `by viewModel()` delegate function: + +```kotlin +class MainActivity : AppCompatActivity() { + + private val viewModel: UserViewModel by viewModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //... + } +} +``` + +That's it, your app is ready. + +:::info +The `by viewModel()` function allows us to retrieve a ViewModel instances, create the associated ViewModel Factory for you and bind it to the lifecycle +::: + +## Start Koin + +We need to start Koin with our Android application. Just call the `startKoin()` function in the application's main entry point, our `MainApplication` class: + +```kotlin +class MainApplication : Application(){ + override fun onCreate() { + super.onCreate() + + startKoin{ + androidLogger() + androidContext(this@MainApplication) + modules(appModule) + } + } +} +``` + +:::info +The `modules()` function in `startKoin` load the given list of modules +::: + +## Koin module: classic or constructor DSL? + +Here is the Koin moduel declaration for our app: + +```kotlin +val appModule = module { + single { HelloRepositoryImpl() } + viewModel { MyViewModel(get()) } +} +``` + +We can write it in a more compact way, by using constructors: + +```kotlin +val appModule = module { + singleOf(::UserRepositoryImpl) { bind() } + viewModelOf(::UserViewModel) +} +``` + +## Verifying your App! + +We can ensure that our Koin configuration is good before launching our app, by verifying our Koin configuration with a simple JUnit Test. + +### Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +// Add Maven Central to your repositories if needed +repositories { + mavenCentral() +} + +dependencies { + + // Koin for Tests + testImplementation "io.insert-koin:koin-test-junit4:$koin_version" +} +``` + +### Checking your modules + +The `verify()` function allow to verify the given Koin modules: + +```kotlin +class CheckModulesTest : KoinTest { + + @Test + fun checkAllModules() { + appModule.verify() + } +} +``` + +With just a JUnit test, you can ensure your definitions configuration are not missing anything! diff --git a/docs/quickstart/android.md b/docs/quickstart/android.md new file mode 100755 index 000000000..96d21e02f --- /dev/null +++ b/docs/quickstart/android.md @@ -0,0 +1,207 @@ +--- +title: Android +--- + +> This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. +> You need around __10/15 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/android) +::: + +## Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +dependencies { + + // Koin for Android + implementation "io.insert-koin:koin-android:$koin_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `MainActivity` class with a Presenter or a ViewModel: + +> Users -> UserRepository -> (Presenter or ViewModel) -> MainActivity + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +```kotlin +val appModule = module { + +} +``` + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } +} +``` + +## Displaying User with Presenter + +Let's write a presenter component to display a user: + +```kotlin +class UserPresenter(private val repository: UserRepository) { + + fun sayHello(name : String) : String{ + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +We declare `UserPresenter` in our Koin module. We declare it as a `factory` definition, to not keep any instance in memory (avoid any leak with Android lifecycle): + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + factory { MyPresenter(get()) } +} +``` + +> The `get()` function allow to ask Koin to resolve the needed dependency. + +## Injecting Dependencies in Android + +The `UserPresenter` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `by inject()` delegate function: + +```kotlin +class MainActivity : AppCompatActivity() { + + private val presenter: UserPresenter by inject() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //... + } +} +``` + +That's it, your app is ready. + +:::info +The `by inject()` function allows us to retrieve Koin instances, in Android components runtime (Activity, fragment, Service...) +::: + +## Start Koin + +We need to start Koin with our Android application. Just call the `startKoin()` function in the application's main entry point, our `MainApplication` class: + +```kotlin +class MainApplication : Application(){ + override fun onCreate() { + super.onCreate() + + startKoin{ + androidLogger() + androidContext(this@MainApplication) + modules(appModule) + } + } +} +``` + +:::info +The `modules()` function in `startKoin` load the given list of modules +::: + +## Koin module: classic or constructor DSL? + +Here is the Koin moduel declaration for our app: + +```kotlin +val appModule = module { + single { HelloRepositoryImpl() } + factory { MyPresenter(get()) } +} +``` + +We can write it in a more compact way, by using constructors: + +```kotlin +val appModule = module { + singleOf(::UserRepositoryImpl) { bind() } + factoryOf(::UserPresenter) +} +``` + +## Verifying your App! + +We can ensure that our Koin configuration is good before launching our app, by verifying our Koin configuration with a simple JUnit Test. + +### Gradle Setup + +Add the Koin Android dependency like below: + +```groovy +// Add Maven Central to your repositories if needed +repositories { + mavenCentral() +} + +dependencies { + + // Koin for Tests + testImplementation "io.insert-koin:koin-test-junit4:$koin_version" +} +``` + +### Checking your modules + +The `verify()` function allow to verify the given Koin modules: + +```kotlin +class CheckModulesTest : KoinTest { + + @Test + fun checkAllModules() { + appModule.verify() + } +} +``` + +With just a JUnit test, you can ensure your definitions configuration are not missing anything! diff --git a/docs/quickstart/junit-test.md b/docs/quickstart/junit-test.md new file mode 100644 index 000000000..a440648a1 --- /dev/null +++ b/docs/quickstart/junit-test.md @@ -0,0 +1,93 @@ +--- +title: JUnit Tests +--- + +> This tutorial lets you test a Kotlin application and use Koin inject and retrieve your components. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kotlin) +::: + +## Gradle Setup + +First, add the Koin dependency like below: + +```groovy +dependencies { + // Koin testing tools + testCompile "io.insert-koin:koin-test:$koin_version" + // Needed JUnit version + testCompile "io.insert-koin:koin-test-junit4:$koin_version" +} +``` + +## Declared dependencies + +We reuse the `koin-core` getting-started project, to use the koin module: + +```kotlin +val helloModule = module { + single { HelloMessageData() } + single { HelloServiceImpl(get()) as HelloService } +} +``` + +## Writing our first Test + +To make our first test, let's write a simple Junit test file and extend it with `KoinTest`. We will be able then, to use `by inject()` operators. + +```kotlin +class HelloAppTest : KoinTest { + + val model by inject() + val service by inject() + + @get:Rule + val koinTestRule = KoinTestRule.create { + printLogger() + modules(helloModule) + } + + @Test + fun `unit test`() { + val helloApp = HelloApplication() + helloApp.sayHello() + + assertEquals(service, helloApp.helloService) + assertEquals("Hey, ${model.message}", service.hello()) + } +} +``` + +> We use the Koin KoinTestRule rule to start/stop our Koin context + +You can even make Mocks directly into MyPresenter, or test MyRepository. Those components doesn't have any link with Koin API. + +```kotlin +class HelloMockTest : KoinTest { + + @get:Rule + val koinTestRule = KoinTestRule.create { + printLogger(Level.DEBUG) + modules(helloModule) + } + + @get:Rule + val mockProvider = MockProviderRule.create { clazz -> + Mockito.mock(clazz.java) + } + + @Test + fun `mock test`() { + val service = declareMock { + given(hello()).willReturn("Hello Mock") + } + + HelloApplication().sayHello() + + Mockito.verify(service,times(1)).hello() + } +} +``` diff --git a/docs/quickstart/kmm.md b/docs/quickstart/kmm.md new file mode 100755 index 000000000..262128315 --- /dev/null +++ b/docs/quickstart/kmm.md @@ -0,0 +1,204 @@ +--- +title: Kotlin Multiplatform Mobile +--- + +> This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. +> You need around __10/15 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kmm) +::: + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our native UI, witha shared Presenter: + +`Users -> UserRepository -> Shared Presenter -> Native UI` + +## The "User" Data + +> All the common/shared code is located in `shared` Gradle project + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Shared Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +module { + single { UserRepositoryImpl() } +} +``` + +## The Shared Presenter + +Let's write a presenter component to display a user: + +```kotlin +class KMPUserPresenter(private val repository: UserRepository) { + + fun sayHello() : String { + val name = DefaultData.DEFAULT_USER.name + val foundUser = repository.findUser(name) + return foundUser?.let { "Hello '$it' from $this" } ?: "User '$name' not found!" + } +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +We declare `UserPresenter` in our Koin module. We declare it as a `factory` definition, to not keep any instance in memory and let the native system hold it: + +```kotlin +fun appModule() = module { + single { UserRepositoryImpl() } + factory { KMPUserPresenter(get()) } +} +``` + +:::note +The Koin module is available as function to run (`appModule()` here), to be easily runned from iOS side, with `initKoin()` function. +::: + +## Injecting Dependencies in Android + +> All the Android app is located in `androidApp` Gradle project + +The `KMPUserPresenter` component will be created, resolving the `UserRepository` instance with it. To get it into our Activity, let's inject it with the `by inject()` delegate function: + +```kotlin +class MainActivity : AppCompatActivity() { + + private val presenter: UserPresenter by inject() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //... + } +} +``` + +That's it, your app is ready. + +:::info +The `by inject()` function allows us to retrieve Koin instances, in Android components runtime (Activity, fragment, Service...) +::: + +We need to start Koin with our Android application. Just call the `startKoin()` function in the application's main entry point, our `MainApplication` class: + +```kotlin +class MainApplication : Application() { + + private val userRepository : UserRepository by inject() + + override fun onCreate() { + super.onCreate() + + startKoin { + androidContext(this@MainApplication) + androidLogger() + modules(appModule() + androidModule) + } + + userRepository.addUsers(DefaultData.DEFAULT_USERS) + } +} +``` + +:::info +The `modules()` function in `startKoin` load the given list of modules +::: + + +## Injecting Dependencies in iOS + +> All the iOS app is located in `iosApp` folder + +The `KMPUserPresenter` component will be created, resolving the `UserRepository` instance with it. To get it into our `ContentView`, we need to create a Helper class to boostrap Koin dependencies: + +```kotlin +class KMPUserPresenterHelper : KoinComponent { + + private val userPresenter : KMPUserPresenter by inject() + + fun sayHello(): String = userPresenter.sayHello() +} +``` + +That's it, you can just call `sayHello()` function from iOS part. + +```swift +import shared + +struct ContentView: View { + let helloText = KMPUserPresenterHelper().sayHello() + + var body: some View { + Text(helloText) + } +} +``` + +We need to start Koin with our iOS application. In the Kotlin shared code, we have a function to let us configure Koin (and setup default data): + +```kotlin +// in HelperKt.kt + +fun initKoin() { + // start Koin + val koinApp = startKoin { + modules(appModule()) + }.koin + + // load default users + koinApp.get().addUsers(DefaultData.DEFAULT_USERS) +} +``` + +Finally in the iOS main entry, we can call the `HelperKt.doInitKoin()` function that is calling our helper function above. + +```swift +@main +struct iOSApp: App { + + init() { + HelperKt.doInitKoin() + } + + //... +} +``` + + diff --git a/docs/quickstart/kotlin-annotations.md b/docs/quickstart/kotlin-annotations.md new file mode 100755 index 000000000..1d48c4708 --- /dev/null +++ b/docs/quickstart/kotlin-annotations.md @@ -0,0 +1,182 @@ +--- +title: Kotlin - Annotations +--- + +> This tutorial lets you write a Kotlin application and use Koin dependency injection to retrieve your components. +> You need around __10 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kotlin-annotations) +::: + +## Setup + +Let's configure the KSP plugin like below in Gradle: + +```groovy +plugins { + // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. + id 'org.jetbrains.kotlin.jvm' version "$kotlin_version" + // Apply the application plugin to add support for building a CLI application in Java. + id "com.google.devtools.ksp" version "$ksp_version" + id 'application' +} + +// KSP - To use generated sources +sourceSets.main { + java.srcDirs("build/generated/ksp/main/kotlin") +} +``` + +Let's setup the dependencies like below: + +```groovy +dependencies { + + // Koin + implementation "io.insert-koin:koin-core:$koin_version" + implementation "io.insert-koin:koin-annotations:$koin_ksp_version" + ksp "io.insert-koin:koin-ksp-compiler:$koin_ksp_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `UserApplication` class: + +> Users -> UserRepository -> UserService -> UserApplication + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Let's declare a `AppModule` module class like below. + +```kotlin +@Module +@ComponentScan("org.koin.sample") +class AppModule +``` + +* We use the `@Module` to declare our class as Koin module +* The `@ComponentScan("org.koin.sample")` allow to scann any Koin definition in `"org.koin.sample"`package + +Let's simply add `@Single` on `UserRepositoryImpl` class to declare it as singleton: + +```kotlin +@Single +class UserRepositoryImpl : UserRepository { + // ... +} +``` + +## The UserService Component + +Let's write the UserService component to request the default user: + +```kotlin +class UserService(private val userRepository: UserRepository) { + + fun getDefaultUser() : User = userRepository.findUser(DefaultData.DEFAULT_USER.name) ?: error("Can't find default user") +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +Let's simply add `@Single` on `UserService` class to declare it as singleton: + +```kotlin +@Single +class UserService(private val userRepository: UserRepository) { + // ... +} +``` + +## Injecting Dependencies in UserApplication + +The `UserApplication` class will help bootstrap instances out of Koin. It will resolve the `UserService`, thanks to `KoinComponent` interface. This allows to inject it with the `by inject()` delegate function: + +```kotlin +class UserApplication : KoinComponent { + + private val userService : UserService by inject() + + // display our data + fun sayHello(){ + val user = userService.getDefaultUser() + val message = "Hello '$user'!" + println(message) + } +} +``` + +That's it, your app is ready. + +:::info +The `by inject()` function allows us to retrieve Koin instances, in any class that extends `KoinComponent` +::: + + +## Start Koin + +We need to start Koin with our application. Just call the `startKoin()` function in the application's main entry point, our `main` function: + +```kotlin +// generated +import org.koin.ksp.generated.* + +fun main() { + startKoin { + modules(AppModule().module) + } + + UserApplication().sayHello() +} +``` + +The Koin module is generated from `AppModule` with the `.module` extension: Just use the `AppModule().module` expression to get the Koin module from the annotations. + + +:::info +The `import org.koin.ksp.generated.*` import is required to allow to use generated Koin module content +::: + +## Compile Time Checks + +Koin Annotations allows to check your Koin configuration at compile time. This is available by jusing the following Gradle option: + +```groovy +ksp { + arg("KOIN_CONFIG_CHECK","true") +} +``` \ No newline at end of file diff --git a/docs/quickstart/kotlin.md b/docs/quickstart/kotlin.md new file mode 100755 index 000000000..c9c70f087 --- /dev/null +++ b/docs/quickstart/kotlin.md @@ -0,0 +1,165 @@ +--- +title: Kotlin +--- + +> This tutorial lets you write a Kotlin application and use Koin dependency injection to retrieve your components. +> You need around __10 min__ to do the tutorial. + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kotlin) +::: + +## Setup + +First, check that the `koin-core` dependency is added like below: + +```groovy +dependencies { + + // Koin for Kotlin apps + compile "io.insert-koin:koin-core:$koin_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `UserApplication` class: + +> Users -> UserRepository -> UserService -> UserApplication + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +```kotlin +val appModule = module { + +} +``` + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } +} +``` + +## The UserService Component + +Let's write the UserService component to request the default user: + +```kotlin +class UserService(private val userRepository: UserRepository) { + + fun getDefaultUser() : User = userRepository.findUser(DefaultData.DEFAULT_USER.name) ?: error("Can't find default user") +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +We declare `UserService` in our Koin module. We declare it as a `single` definition: + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + single { UserService(get()) } +} +``` + +> The `get()` function allow to ask Koin to resolve the needed dependency. + +## Injecting Dependencies in UserApplication + +The `UserApplication` class will help bootstrap instances out of Koin. It will resolve the `UserService`, thanks to `KoinComponent` interface. This allows to inject it with the `by inject()` delegate function: + +```kotlin +class UserApplication : KoinComponent { + + private val userService : UserService by inject() + + // display our data + fun sayHello(){ + val user = userService.getDefaultUser() + val message = "Hello '$user'!" + println(message) + } +} +``` + +That's it, your app is ready. + +:::info +The `by inject()` function allows us to retrieve Koin instances, in any class that extends `KoinComponent` +::: + + +## Start Koin + +We need to start Koin with our application. Just call the `startKoin()` function in the application's main entry point, our `main` function: + +```kotlin +fun main() { + startKoin { + modules(appModule) + } + + UserApplication().sayHello() +} +``` + +:::info +The `modules()` function in `startKoin` load the given list of modules +::: + +## Koin module: classic or constructor DSL? + +Here is the Koin moduel declaration for our app: + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + single { UserService(get()) } +} +``` + +We can write it in a more compact way, by using constructors: + +```kotlin +val appModule = module { + singleOf(::UserRepositoryImpl) { bind() } + singleOf(::UserService) +} +``` diff --git a/docs/quickstart/ktor.md b/docs/quickstart/ktor.md new file mode 100755 index 000000000..5806c43d7 --- /dev/null +++ b/docs/quickstart/ktor.md @@ -0,0 +1,184 @@ +--- +title: Ktor +--- + +> Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language. We will use Ktor here, to build a simple web application. + +Let's go 🚀 + +## Get the code + +:::info +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/ktor) +::: + +## Gradle Setup + +First, add the Koin dependency like below: + +```kotlin +dependencies { + // Koin for Kotlin apps + implementation "io.insert-koin:koin-ktor:$koin_version" + implementation "io.insert-koin:koin-logger-slf4j:$koin_version" +} +``` + +## Application Overview + +The idea of the application is to manage a list of users, and display it in our `UserApplication` class: + +> Users -> UserRepository -> UserService -> UserApplication + +## The "User" Data + +We will manage a collection of Users. Here is the data class: + +```kotlin +data class User(val name : String) +``` + +We create a "Repository" component to manage the list of users (add users or find one by name). Here below, the `UserRepository` interface and its implementation: + +```kotlin +interface UserRepository { + fun findUser(name : String): User? + fun addUsers(users : List) +} + +class UserRepositoryImpl : UserRepository { + + private val _users = arrayListOf() + + override fun findUser(name: String): User? { + return _users.firstOrNull { it.name == name } + } + + override fun addUsers(users : List) { + _users.addAll(users) + } +} +``` + +## The Koin module + +Use the `module` function to declare a Koin module. A Koin module is the place where we define all our components to be injected. + +```kotlin +val appModule = module { + +} +``` + +Let's declare our first component. We want a singleton of `UserRepository`, by creating an instance of `UserRepositoryImpl` + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } +} +``` + +## The UserService Component + +Let's write the UserService component to request the default user: + +```kotlin +class UserService(private val userRepository: UserRepository) { + + fun getDefaultUser() : User = userRepository.findUser(DefaultData.DEFAULT_USER.name) ?: error("Can't find default user") +} +``` + +> UserRepository is referenced in UserPresenter`s constructor + +We declare `UserService` in our Koin module. We declare it as a `single` definition: + +```kotlin +val appModule = module { + single { UserRepositoryImpl() } + single { UserService(get()) } +} +``` + +## HTTP Controller + +Finally, we need an HTTP Controller to create the HTTP Route. In Ktor is will be expressed through an Ktor extension function: + +```kotlin +fun Application.main() { + + // Lazy inject HelloService + val service by inject() + + // Routing section + routing { + get("/hello") { + call.respondText(service.sayHello()) + } + } +} +``` + +Check that your `application.conf` is configured like below, to help start the `Application.main` function: + +```kotlin +ktor { + deployment { + port = 8080 + + // For dev purpose + //autoreload = true + //watch = [org.koin.sample] + } + + application { + modules = [ org.koin.sample.UserApplicationKt.main ] + } +} +``` + +## Declare your dependencies + +Let's assemble our components with a Koin module: + +```kotlin +val appModule = module { + singleOf(::UserRepositoryImpl) { bind() } + singleOf(::UserService) +} +``` + +## Start and Inject + +Finally, let's start Koin from Ktor: + +```kotlin +fun Application.main() { + install(Koin) { + slf4jLogger() + modules(appModule) + } + + // Lazy inject HelloService + val service by inject() + service.saveDefaultUsers() + + // Routing section + routing { + get("/hello") { + call.respondText(service.sayHello()) + } + } +} +``` + +Let's start Ktor: + +```kotlin +fun main(args: Array) { + // Start Ktor + embeddedServer(Netty, commandLineEnvironment(args)).start(wait = true) +} +``` + +That's it! You're ready to go. Check the `http://localhost:8080/hello` url! From dc932c69601ceed0c88955663aa02f1332a7bfce Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 15:20:05 +0100 Subject: [PATCH 67/77] fix #1767 - documentation links --- docs/quickstart/{kmm.md => kmp.md} | 4 ++-- docs/reference/koin-android/dsl-update.md | 2 +- docs/reference/koin-android/instrumented-testing.md | 2 +- docs/reference/koin-android/modules-android.md | 2 +- docs/reference/koin-android/start.md | 2 +- docs/reference/koin-compose/isolated-context.md | 2 +- docs/reference/koin-test/testing.md | 2 +- docs/setup/koin.md | 10 +++++----- 8 files changed, 13 insertions(+), 13 deletions(-) rename docs/quickstart/{kmm.md => kmp.md} (98%) diff --git a/docs/quickstart/kmm.md b/docs/quickstart/kmp.md similarity index 98% rename from docs/quickstart/kmm.md rename to docs/quickstart/kmp.md index 262128315..764edbebf 100755 --- a/docs/quickstart/kmm.md +++ b/docs/quickstart/kmp.md @@ -1,5 +1,5 @@ --- -title: Kotlin Multiplatform Mobile +title: Kotlin Multiplatform - Mobile Apps --- > This tutorial lets you write an Android application and use Koin dependency injection to retrieve your components. @@ -8,7 +8,7 @@ title: Kotlin Multiplatform Mobile ## Get the code :::info -[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kmm) +[The source code is available at on Github](https://github.com/InsertKoinIO/koin-getting-started/tree/main/kmp) ::: ## Application Overview diff --git a/docs/reference/koin-android/dsl-update.md b/docs/reference/koin-android/dsl-update.md index 972911e48..76be6a817 100644 --- a/docs/reference/koin-android/dsl-update.md +++ b/docs/reference/koin-android/dsl-update.md @@ -6,7 +6,7 @@ title: Constructor DSL for Android Koin now offer a new kind of DSL keyword that allow you to target a class constructor directly, and avoid to have type your definition within a lambda expression. -Check the new [Constructor DSL](../koin-core/dsl-update.md#constructor-dsl-since-32) section for more details. +Check the new [Constructor DSL](/docs/reference/koin-core/dsl-update.md#constructor-dsl-since-32) section for more details. For Android, this implies the following new constructor DSL Keyword: diff --git a/docs/reference/koin-android/instrumented-testing.md b/docs/reference/koin-android/instrumented-testing.md index 32454e1f0..f25ff911c 100644 --- a/docs/reference/koin-android/instrumented-testing.md +++ b/docs/reference/koin-android/instrumented-testing.md @@ -4,7 +4,7 @@ title: Android Instrumented Testing ## Override production modules in a custom Application class -Unlike [unit tests](../koin-test/testing.md), where you effectively call start Koin in each test class (i.e. `startKoin` or `KoinTestExtension`), in Instrumented tests Koin is started by your `Application` class. +Unlike [unit tests](/docs/reference/koin-test/testing.md), where you effectively call start Koin in each test class (i.e. `startKoin` or `KoinTestExtension`), in Instrumented tests Koin is started by your `Application` class. For overriding production Koin modules, `loadModules` and `unloadModules` are often unsafe because the changes are not applied immediately. Instead, the recommended approach is to add a `module` of your overrides to `modules` used by `startKoin` in the `Application` class. If you want to keep the class that extends `Application` of your application untouched, you can create another one inside the `AndroidTest` package like: diff --git a/docs/reference/koin-android/modules-android.md b/docs/reference/koin-android/modules-android.md index 4fda60bc6..992ddccb4 100644 --- a/docs/reference/koin-android/modules-android.md +++ b/docs/reference/koin-android/modules-android.md @@ -47,7 +47,7 @@ class MainApplication : Application() { ``` Up to you to organise your self per Gradle module, and gather several Koin modules. -> Check [Koin Modules Section](../koin-core/modules) for more details +> Check [Koin Modules Section](/docs/reference/koin-core/modules) for more details ## Module Includes (since 3.2) diff --git a/docs/reference/koin-android/start.md b/docs/reference/koin-android/start.md index e108ddacc..f495b08f6 100644 --- a/docs/reference/koin-android/start.md +++ b/docs/reference/koin-android/start.md @@ -2,7 +2,7 @@ title: Start Koin on Android --- -The `koin-android` project is dedicated to provide Koin powers to Android world. See the [Android setup](../../setup/koin#android) section for more details. +The `koin-android` project is dedicated to provide Koin powers to Android world. See the [Android setup](/docs/setup/koin#android) section for more details. ## From your Application class diff --git a/docs/reference/koin-compose/isolated-context.md b/docs/reference/koin-compose/isolated-context.md index f93654928..a2a18a6d2 100644 --- a/docs/reference/koin-compose/isolated-context.md +++ b/docs/reference/koin-compose/isolated-context.md @@ -2,7 +2,7 @@ title: Isolated Context with Compose --- -With a Compose application, you can work the same way with an [isolated context](../koin-core/context-isolation.md) to deal with SDK or white label application, in order to not mix your Koin definitions with an end user's one. +With a Compose application, you can work the same way with an [isolated context](/docs/reference/koin-core/context-isolation.md) to deal with SDK or white label application, in order to not mix your Koin definitions with an end user's one. ## Define isolated context diff --git a/docs/reference/koin-test/testing.md b/docs/reference/koin-test/testing.md index 6d2d36a6e..f3b272681 100644 --- a/docs/reference/koin-test/testing.md +++ b/docs/reference/koin-test/testing.md @@ -4,7 +4,7 @@ title: Injecting in Tests ## Making your test a KoinComponent with KoinTest -*Warning*: This does not apply to Android Instrumented tests. For Instrumented testing with Koin, please see [Android Instrumented Testing](../koin-android/instrumented-testing.md) +*Warning*: This does not apply to Android Instrumented tests. For Instrumented testing with Koin, please see [Android Instrumented Testing](/docs/reference/koin-android/instrumented-testing.md) By tagging your class `KoinTest`, your class become a `KoinComponent` and bring you: diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 870bd4cc1..a1ba5e9c5 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -87,7 +87,7 @@ dependencies { ``` :::info -From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin App Tutorial](../quickstart/kotlin) +From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin App Tutorial](/docs/quickstart/kotlin) ::: ### **Android** @@ -128,7 +128,7 @@ dependencies { ``` :::info -From now you can continue on Koin Tutorials to learn about using Koin: [Android App Tutorial](../quickstart/android-viewmodel) +From now you can continue on Koin Tutorials to learn about using Koin: [Android App Tutorial](/docs/quickstart/android-viewmodel) ::: ### **Android Jetpack Compose** @@ -154,7 +154,7 @@ class MainApplication : Application() { ``` :::info -From now you can continue on Koin Tutorials to learn about using Koin: [Android Compose App Tutorial](../quickstart/android-compose) +From now you can continue on Koin Tutorials to learn about using Koin: [Android Compose App Tutorial](/docs/quickstart/android-compose) ::: @@ -169,7 +169,7 @@ dependencies { ``` :::info -From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin Multiplatform App Tutorial](../quickstart/kmm) +From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin Multiplatform App Tutorial](/docs/quickstart/kmm) ::: ### **Ktor** @@ -197,7 +197,7 @@ fun Application.main() { ``` :::info -From now you can continue on Koin Tutorials to learn about using Koin: [Ktor App Tutorial](../quickstart/ktor) +From now you can continue on Koin Tutorials to learn about using Koin: [Ktor App Tutorial](/docs/quickstart/ktor) ::: From 1f1eaa397a81325afcb99982cefddd6f9766b17e Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 15:40:50 +0100 Subject: [PATCH 68/77] Track VM key + change examples version --- examples/gradle/versions.gradle | 2 +- .../src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/gradle/versions.gradle b/examples/gradle/versions.gradle index b71de1cf8..b4bb44c76 100644 --- a/examples/gradle/versions.gradle +++ b/examples/gradle/versions.gradle @@ -2,7 +2,7 @@ ext { // Kotlin kotlin_version = '1.9.21' // Koin Versions - koin_version = '3.6.0-alpha1' + koin_version = '3.5.4-rc-1' koin_android_version = koin_version coroutines_version = "1.7.3" ktor_version = "2.3.7" diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt index 1e8a9ac1c..003a271cb 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt @@ -38,6 +38,7 @@ fun resolveViewModel( val factory = KoinViewModelFactory(vmClass, scope, qualifier, parameters) val provider = ViewModelProvider(viewModelStore, factory, extras) val vmKey = getViewModelKey(qualifier, scope, key) + scope.logger.debug("[vm_key] - $modelClass = $vmKey") return when { vmKey != null -> provider[vmKey, modelClass] else -> provider[modelClass] From f3fc38c2c10fb02e97be39693c403c4ddc7ebbf0 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 17:49:38 +0100 Subject: [PATCH 69/77] Allow VM key to be generated against Key & Qualifier. VM scope is only limited to root scope to avoid leaking from any Activity/Fragment context. ScopeViewModel allow to work on ViewModel scope space. --- .../components/mvvm/ExtSimpleViewModel.kt | 6 ---- .../components/mvvm/MyScopeViewModel.kt | 19 ++++++++++ .../components/mvvm/MyScopeViewModel2.kt | 12 +++++++ .../components/mvvm/SavedStateViewModel.kt | 2 +- .../sandbox/components/scope/Session.kt | 6 ++++ .../org/koin/sample/sandbox/di/AppModule.kt | 24 ++++++++----- .../koin/sample/sandbox/mvvm/MVVMActivity.kt | 27 ++++++-------- .../koin/sample/sandbox/mvvm/MVVMFragment.kt | 14 -------- .../org/koin/androidx/scope/ScopeViewModel.kt | 18 ++++++++++ .../koin/androidx/viewmodel/GetViewModel.kt | 35 +++++++++++++------ .../android/viewmodel/ViewModelKeyTest.kt | 20 +++-------- .../androidx/viewmodel/GetViewModelTest.kt | 4 ++- 12 files changed, 114 insertions(+), 73 deletions(-) delete mode 100644 examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/ExtSimpleViewModel.kt create mode 100644 examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel.kt create mode 100644 examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel2.kt create mode 100644 projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/ExtSimpleViewModel.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/ExtSimpleViewModel.kt deleted file mode 100644 index bd8b7d75d..000000000 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/ExtSimpleViewModel.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.koin.sample.sandbox.components.mvvm - -import androidx.lifecycle.ViewModel -import org.koin.sample.sandbox.components.scope.Session - -class ExtSimpleViewModel(val session: Session) : ViewModel() \ No newline at end of file diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel.kt new file mode 100644 index 000000000..e4953becd --- /dev/null +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel.kt @@ -0,0 +1,19 @@ +package org.koin.sample.sandbox.components.mvvm + +import androidx.lifecycle.ViewModel +import org.koin.core.component.KoinScopeComponent +import org.koin.core.component.createScope +import org.koin.core.scope.Scope +import org.koin.sample.sandbox.components.scope.Session + +class MyScopeViewModel : ViewModel(), KoinScopeComponent { + + override val scope: Scope = createScope(this) + + val session by scope.inject() + + override fun onCleared() { + super.onCleared() + scope.close() + } +} \ No newline at end of file diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel2.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel2.kt new file mode 100644 index 000000000..c94f2c574 --- /dev/null +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/MyScopeViewModel2.kt @@ -0,0 +1,12 @@ +package org.koin.sample.sandbox.components.mvvm + +import org.koin.androidx.scope.ScopeViewModel +import org.koin.core.annotation.KoinExperimentalAPI +import org.koin.sample.sandbox.components.scope.Session + +@OptIn(KoinExperimentalAPI::class) +class MyScopeViewModel2 : ScopeViewModel() { + + val session by scope.inject() + +} \ No newline at end of file diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/SavedStateViewModel.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/SavedStateViewModel.kt index 8bf281ee0..cbd2b4d00 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/SavedStateViewModel.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/mvvm/SavedStateViewModel.kt @@ -9,6 +9,6 @@ class SavedStateViewModel(val handle: SavedStateHandle, val id: String, val serv init { val get = handle.get(id) println("handle: $get") - handle.set(id,UUID.randomUUID().toString()) + handle[id] = UUID.randomUUID().toString() } } \ No newline at end of file diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/scope/Session.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/scope/Session.kt index c1813767d..be37d41c7 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/scope/Session.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/components/scope/Session.kt @@ -6,6 +6,12 @@ class Session { var id: String = UUID.randomUUID().toString() } +class SessionConsumer(private val session: Session){ + + fun getSessionId() = session.id + +} + class SessionActivity { val id: String = UUID.randomUUID().toString() } diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/di/AppModule.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/di/AppModule.kt index 955523505..3676d3aef 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/di/AppModule.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/di/AppModule.kt @@ -8,7 +8,6 @@ import org.koin.core.module.dsl.* import org.koin.core.module.includes import org.koin.core.qualifier.named import org.koin.dsl.lazyModule -import org.koin.dsl.module import org.koin.sample.sandbox.components.Counter import org.koin.sample.sandbox.components.SCOPE_ID import org.koin.sample.sandbox.components.SCOPE_SESSION @@ -21,6 +20,7 @@ import org.koin.sample.sandbox.components.mvp.ScopedPresenter import org.koin.sample.sandbox.components.mvvm.* import org.koin.sample.sandbox.components.scope.Session import org.koin.sample.sandbox.components.scope.SessionActivity +import org.koin.sample.sandbox.components.scope.SessionConsumer import org.koin.sample.sandbox.mvp.MVPActivity import org.koin.sample.sandbox.mvvm.MVVMActivity import org.koin.sample.sandbox.mvvm.MVVMFragment @@ -45,13 +45,13 @@ val mvpModule = lazyModule { scope { scopedOf(::ScopedPresenter)// { (id: String) -> ScopedPresenter(id, get()) } + } } val mvvmModule = lazyModule { viewModelOf(::SimpleViewModel)// { (id: String) -> SimpleViewModel(id, get()) } - viewModelOf(::SimpleViewModel) { named("vm1") } //{ (id: String) -> SimpleViewModel(id, get()) } viewModel(named("vm2")) { (id: String) -> SimpleViewModel(id, get()) } @@ -61,22 +61,30 @@ val mvvmModule = lazyModule { // viewModel { ViewModelImpl(get()) } viewModelOf(::ViewModelImpl) { bind() } - scope { + viewModelOf(::MyScopeViewModel) + scope { + scopedOf(::Session) + } + viewModelOf(::MyScopeViewModel2) + scope { + scopedOf(::Session) + scopedOf(::SessionConsumer) + } + + viewModelOf(::SavedStateViewModel) { named("vm2") } + + scope { scopedOf(::Session) fragmentOf(::MVVMFragment) // { MVVMFragment(get()) } - viewModelOf(::ExtSimpleViewModel) - viewModelOf(::ExtSimpleViewModel) { named("ext") } - viewModelOf(::SavedStateViewModel) { named("vm2") } scoped { MVVMPresenter1(get()) } scoped { MVVMPresenter2(get()) } } scope { scoped { (id: String) -> ScopedPresenter(id, get()) } + // to retrieve from parent // scopedOf(::Session) - viewModelOf(::ExtSimpleViewModel) - viewModelOf(::ExtSimpleViewModel) { named("ext") } } } diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt index 9da57428c..4372212b3 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt @@ -8,35 +8,28 @@ import org.koin.android.ext.android.inject import org.koin.androidx.fragment.android.replace import org.koin.androidx.fragment.android.setupKoinFragmentFactory import org.koin.androidx.scope.ScopeActivity -import org.koin.androidx.viewmodel.ext.android.getViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.androidx.viewmodel.ext.android.viewModelForClass import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named import org.koin.sample.sandbox.R -import org.koin.sample.sandbox.components.ID import org.koin.sample.sandbox.components.mvp.FactoryPresenter import org.koin.sample.sandbox.components.mvvm.* import org.koin.sample.sandbox.components.scope.Session +import org.koin.sample.sandbox.components.scope.SessionConsumer import org.koin.sample.sandbox.scope.ScopedActivityA import org.koin.sample.sandbox.utils.navigateTo class MVVMActivity : ScopeActivity(contentLayoutId = R.layout.mvvm_activity) { - lateinit var simpleViewModel: SimpleViewModel //by viewModel { parametersOf(ID) } - + val vm: SimpleViewModel by viewModel { parametersOf("vm") } val vm1: SimpleViewModel by viewModel(named("vm1")) { parametersOf("vm1") } val vm2: SimpleViewModel by viewModel(named("vm2")) { parametersOf("vm2") } - val scopeVm: ExtSimpleViewModel by viewModel() - val extScopeVm: ExtSimpleViewModel by viewModel(named("ext")) - - // val savedVm: SavedStateViewModel by stateViewModel { parametersOf("vm1") } - val savedVm: SavedStateViewModel by viewModel { parametersOf("vm1") } + val scopeVm1: MyScopeViewModel by viewModel() + val scopeVm2: MyScopeViewModel2 by viewModel() - // val state = Bundle().apply { putString("id", "vm1") } -// val stateVM: SavedStateBundleViewModel by stateViewModel(state = { state }) val stateVM: SavedStateBundleViewModel by viewModel() + val savedVm: SavedStateViewModel by viewModel { parametersOf("vm1") } val abstractVM : AbstractViewModel by viewModel() @@ -60,8 +53,6 @@ class MVVMActivity : ScopeActivity(contentLayoutId = R.layout.mvvm_activity) { navigateTo(isRoot = true) } -// simpleViewModel = viewModelForClass(SimpleViewModel::class, owner = this).value - checks() } @@ -77,14 +68,18 @@ class MVVMActivity : ScopeActivity(contentLayoutId = R.layout.mvvm_activity) { private fun checks() { assert(abstractVM is ViewModelImpl) - assert(scopeVm.session.id == extScopeVm.session.id) assert(stateVM.result == "vm1") + assert(vm1.id != vm.id) assert(vm1.id != vm2.id) val p1 = scope.get() val p2 = scope.get() - assert(p1.ctx == this) assert(p2.ctx == getKoin().get()) + + assert(scopeVm1.session.id == scopeVm1.scope.get().id) + assert(scopeVm2.session.id == scopeVm2.scope.get().id) + assert(scopeVm2.scope.get().getSessionId() == scopeVm2.scope.get().id) + assert(scopeVm1.session.id != scopeVm2.session.id) } } \ No newline at end of file diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt index a816ca157..2137d06fb 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt @@ -11,13 +11,10 @@ import org.koin.androidx.scope.requireScopeActivity import org.koin.androidx.viewmodel.ext.android.activityViewModel import org.koin.androidx.viewmodel.ext.android.getActivityViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.androidx.viewmodel.ext.android.viewModelForClass import org.koin.core.parameter.parametersOf -import org.koin.core.qualifier.named import org.koin.core.scope.Scope import org.koin.sample.sandbox.R import org.koin.sample.sandbox.components.ID -import org.koin.sample.sandbox.components.mvvm.ExtSimpleViewModel import org.koin.sample.sandbox.components.mvvm.SavedStateViewModel import org.koin.sample.sandbox.components.mvvm.SimpleViewModel import org.koin.sample.sandbox.components.scope.Session @@ -27,14 +24,8 @@ class MVVMFragment(private val session: Session) : Fragment(R.layout.mvvm_fragme override val scope: Scope by fragmentScope() val simpleViewModel: SimpleViewModel by viewModel { parametersOf(ID) } - - // Generic KClass Access - val scopeVm: ExtSimpleViewModel by viewModelForClass(ExtSimpleViewModel::class) - val extScopeVm: ExtSimpleViewModel by viewModel(named("ext")) - val shared: SimpleViewModel by activityViewModel { parametersOf(ID) } - val sharedSaved: SavedStateViewModel by activityViewModel { parametersOf(ID) } val saved by viewModel { parametersOf(ID) } val saved2 by viewModel { parametersOf(ID) } @@ -48,13 +39,8 @@ class MVVMFragment(private val session: Session) : Fragment(R.layout.mvvm_fragme checkNotNull(session) assert(shared != simpleViewModel) - // TODO Handle shared isntance - out of Scope -// assert((requireActivity() as MVVMActivity).simpleViewModel == shared) -// assert((requireActivity() as MVVMActivity).savedVm == sharedSaved) - assert((requireActivity() as MVVMActivity).savedVm != saved) assert((requireActivity() as MVVMActivity).savedVm != saved2) - assert(scopeVm.session.id == extScopeVm.session.id) val shared2 = getActivityViewModel { parametersOf(ID) } diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt new file mode 100644 index 000000000..ff04eafd0 --- /dev/null +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt @@ -0,0 +1,18 @@ +package org.koin.androidx.scope + +import androidx.lifecycle.ViewModel +import org.koin.core.annotation.KoinExperimentalAPI +import org.koin.core.component.KoinScopeComponent +import org.koin.core.component.createScope +import org.koin.core.scope.Scope + +@KoinExperimentalAPI +abstract class ScopeViewModel : ViewModel(), KoinScopeComponent { + + override val scope: Scope = createScope(this) + + override fun onCleared() { + super.onCleared() + scope.close() + } +} \ No newline at end of file diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt index 003a271cb..6af9b24b9 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStore import androidx.lifecycle.viewmodel.CreationExtras import org.koin.androidx.viewmodel.factory.KoinViewModelFactory +import org.koin.core.Koin import org.koin.core.annotation.KoinInternalApi import org.koin.core.parameter.ParametersDefinition import org.koin.core.parameter.ParametersHolder @@ -25,6 +26,7 @@ import kotlin.reflect.KClass * @param parameters - for instance building injection */ @KoinInternalApi +@Deprecated("scope is not used for ViewModel creation") fun resolveViewModel( vmClass: KClass, viewModelStore: ViewModelStore, @@ -33,12 +35,26 @@ fun resolveViewModel( qualifier: Qualifier? = null, scope: Scope, parameters: ParametersDefinition? = null, +): T { + return resolveViewModel(vmClass, viewModelStore, key, extras, qualifier, scope.getKoin(), parameters) +} + +@KoinInternalApi +fun resolveViewModel( + vmClass: KClass, + viewModelStore: ViewModelStore, + key: String? = null, + extras: CreationExtras, + qualifier: Qualifier? = null, + koin : Koin, + parameters: ParametersDefinition? = null, ): T { val modelClass: Class = vmClass.java - val factory = KoinViewModelFactory(vmClass, scope, qualifier, parameters) + val factory = KoinViewModelFactory(vmClass, koin.scopeRegistry.rootScope, qualifier, parameters) val provider = ViewModelProvider(viewModelStore, factory, extras) - val vmKey = getViewModelKey(qualifier, scope, key) - scope.logger.debug("[vm_key] - $modelClass = $vmKey") + val vmKey = getViewModelKey(qualifier, key) + +// koin.logger.debug("[vm_key] - provider:$provider - class:$modelClass = $vmKey (q:'${qualifier?.value}', k:'$key')") return when { vmKey != null -> provider[vmKey, modelClass] else -> provider[modelClass] @@ -46,14 +62,11 @@ fun resolveViewModel( } @KoinInternalApi -internal fun getViewModelKey(qualifier: Qualifier?, scope: Scope, key: String?): String? { - return if (qualifier == null && key == null && scope.isRoot) { - null - } else { - val q = qualifier?.value ?: "" - val k = key ?: "" - val s = if (!scope.isRoot) scope.id else "" - "$q$k$s" +internal fun getViewModelKey(qualifier: Qualifier?, key: String?): String? { + return when { + qualifier != null -> qualifier.value + (key?.let { "_$it" } ?: "") + key != null -> key + else -> null } } diff --git a/projects/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt b/projects/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt index 7882d5b87..54a708ded 100644 --- a/projects/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt +++ b/projects/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt @@ -13,32 +13,20 @@ class ViewModelKeyTest { @OptIn(KoinInternalApi::class) @Test fun generate_right_key() { - val koin = koinApplication().koin - val root = koin.scopeRegistry.rootScope - val q = StringQualifier("_qualifier_") - val scope = Scope(StringQualifier("_q_"), id = "_id_", _koin = koin, isRoot = false) val key = "_KEY_" assertEquals( - null, getViewModelKey(qualifier = null, scope = root, key = null) - ) - assertEquals( - q.value, getViewModelKey(qualifier = q, scope = root, key = null) + null, getViewModelKey(qualifier = null, key = null) ) assertEquals( - key, getViewModelKey(qualifier = null, scope = root, key = key) + q.value, getViewModelKey(qualifier = q, key = null) ) assertEquals( - scope.id, getViewModelKey(qualifier = null, scope = scope, key = null) + q.value + "_$key", getViewModelKey(qualifier = q, key = key) ) - - assertEquals( - key + scope.id, getViewModelKey(qualifier = null, scope = scope, key = key) - ) - assertEquals( - q.value + key + scope.id, getViewModelKey(qualifier = q, scope = scope, key = key) + key, getViewModelKey(qualifier = null, key = key) ) } } \ No newline at end of file diff --git a/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt index e12e7818d..d7ccfa3d4 100644 --- a/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt +++ b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt @@ -12,6 +12,7 @@ import org.koin.androidx.viewmodel.resolveViewModel import org.koin.core.annotation.KoinInternalApi import org.koin.core.qualifier.Qualifier import org.koin.core.scope.Scope +import org.koin.dsl.koinApplication @KoinInternalApi class GetViewModelTest { @@ -19,7 +20,8 @@ class GetViewModelTest { private val viewModelStore: ViewModelStore = mockk(relaxed = true) private val extras: CreationExtras = mockk() private val qualifier: Qualifier = mockk() - private val scope: Scope = mockk() + private val koin = koinApplication { }.koin + private val scope: Scope = koin.scopeRegistry.rootScope @Test fun `should return a ViewModel with a default Android key`() { From 61401f1b92d0cfcc752f0f6569b13ae26518f76b Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 18:09:44 +0100 Subject: [PATCH 70/77] Fix tests and add doc --- .../org/koin/androidx/scope/ScopeViewModel.kt | 16 ++++++++++ .../koin/androidx/viewmodel/GetViewModel.kt | 12 +++++++ .../androidx/viewmodel/GetViewModelTest.kt | 31 +------------------ 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt index ff04eafd0..917ca6f05 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/scope/ScopeViewModel.kt @@ -6,13 +6,29 @@ import org.koin.core.component.KoinScopeComponent import org.koin.core.component.createScope import org.koin.core.scope.Scope +/** + * Class to help support Koin Scope in a ViewModel + * create directly a scope instance for current ViewModel + * + * allow to intercept before scope closing with `onCloseScope`, to be overriden + * + * Destroy linked scope with `onCleared` + * + * @author Arnaud Giuliani + */ @KoinExperimentalAPI abstract class ScopeViewModel : ViewModel(), KoinScopeComponent { override val scope: Scope = createScope(this) + /** + * To override to add behavior before closing Scope + */ + open fun onCloseScope(){} + override fun onCleared() { super.onCleared() + onCloseScope() scope.close() } } \ No newline at end of file diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt index 6af9b24b9..2fbe5f51b 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt @@ -39,6 +39,17 @@ fun resolveViewModel( return resolveViewModel(vmClass, viewModelStore, key, extras, qualifier, scope.getKoin(), parameters) } +/** + * Resolve a ViewModel instance + * + * @param vmClass + * @param viewModelStore + * @param key + * @param extras - @see CreationExtras + * @param qualifier + * @param koin + * @param parameters - for instance building injection + */ @KoinInternalApi fun resolveViewModel( vmClass: KClass, @@ -54,6 +65,7 @@ fun resolveViewModel( val provider = ViewModelProvider(viewModelStore, factory, extras) val vmKey = getViewModelKey(qualifier, key) + //To help track Keys // koin.logger.debug("[vm_key] - provider:$provider - class:$modelClass = $vmKey (q:'${qualifier?.value}', k:'$key')") return when { vmKey != null -> provider[vmKey, modelClass] diff --git a/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt index d7ccfa3d4..5cc338b02 100644 --- a/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt +++ b/projects/android/koin-android/src/test/java/org/koin/test/androidx/viewmodel/GetViewModelTest.kt @@ -26,7 +26,6 @@ class GetViewModelTest { @Test fun `should return a ViewModel with a default Android key`() { val classToTest = ViewModel::class - every { scope.isRoot } returns true val firstViewModel = resolveViewModel( classToTest, @@ -49,10 +48,7 @@ class GetViewModelTest { val classToTest = ViewModel::class val qualifierName = "qualifier" val key = "key" - val scopeId = "scopeId" - every { scope.isRoot } returns false - every { scope.id } returns scopeId every { qualifier.value } returns qualifierName val viewModel = resolveViewModel( @@ -65,41 +61,17 @@ class GetViewModelTest { null ) - val koinVmKey = "$qualifierName$key$scopeId" + val koinVmKey = "${qualifierName}_$key" assertNotNull(viewModel) verify { viewModelStore[koinVmKey] } } - @Test - fun `should return a ViewModel considering only a non root scope identifier`() { - val classToTest = ViewModel::class - val scopeId = "scopeId" - - every { scope.isRoot } returns false - every { scope.id } returns scopeId - - val viewModel = resolveViewModel( - classToTest, - viewModelStore, - null, - extras, - null, - scope, - null - ) - - assertNotNull(viewModel) - verify { viewModelStore[scopeId] } - } - @Test fun `should return a ViewModel considering a key and a root scope identifier`() { val classToTest = ViewModel::class val key = "key" - every { scope.isRoot } returns true - val viewModel = resolveViewModel( classToTest, viewModelStore, @@ -119,7 +91,6 @@ class GetViewModelTest { val classToTest = ViewModel::class val qualifierValue = "qualifier" - every { scope.isRoot } returns true every { qualifier.value } returns qualifierValue val viewModel = resolveViewModel( From a53ad944806f57e206bb67ea73dd594ca5979b00 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 18:25:51 +0100 Subject: [PATCH 71/77] ViewModel online doc update --- docs/reference/koin-android/scope.md | 54 +++++++++++++++++++++++- docs/reference/koin-android/viewmodel.md | 8 ++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index 2cfe3c6bb..ecb3a4749 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -60,7 +60,7 @@ val androidModule = module { on it and can't totally drop it via garbage collection. ::: -## Scope for Android Components (3.2.1 update) +## Scope for Android Components (since 3.2.1) ### Declare an Android Scope @@ -164,6 +164,58 @@ class MyActivity() : AppCompatActivity(contentLayoutId), AndroidScopeComponent { If you try to access Scope from `onDestroy()` function, scope will be already closed. ::: +### ViewModel Scope (since 3.5.4) + +ViewModel is only created against root scope to avoid any leaking (leaking Activity or Fragment ...). This guard for the visibility problem, where ViewModel could have access to incompatible scopes. + +:::note +If you ViewModel can't get access to a dependency, check in which scope it has been declared. +::: + + +:::note +If you _really_ need to leak a dependency from outside a ViewModel scope, you can use "injected parameters" to pass some objects to your ViewModel. +::: + +`ScopeViewModel` is a new class to help work on ViewModel scope. This handle ViewModel's scope creation, and provide `scope` property to allow inject with `by scope.inject()`: + +```kotlin +module { + viewModelOf(::MyScopeViewModel) + scope { + scopedOf(::Session) + } +} + +class MyScopeViewModel : ScopeViewModel() { + + // on onCleared, scope is closed + + // injected from current MyScopeViewModel's scope + val session by scope.inject() + +} +``` + +By using `ScopeViewModel` you can also overrode `onCloseScope()` function, to run code before scope is being closed. + +:::note +All instances inside a ViewModel scope have the same visibility and will survive for lifetime of ViewModel instance, until ViewModel's onCleared function is called +::: + +For example, Once an Activity or fragment has created a ViewModel, the associated scope is created: + +```kotlin +class MyActivity : AppCompatActivity() { + + // Create ViewModel and its scope + val myViewModel by viewModel() + +} +``` + +Once your ViewModel is created, all associated dependencies from within this scope can be created and injected. + ## Scope Links Scope links allow to share instances between components with custom scopes. diff --git a/docs/reference/koin-android/viewmodel.md b/docs/reference/koin-android/viewmodel.md index 931bbd9f7..a2e4cbbdf 100644 --- a/docs/reference/koin-android/viewmodel.md +++ b/docs/reference/koin-android/viewmodel.md @@ -41,6 +41,10 @@ class DetailActivity : AppCompatActivity() { } ``` +:::note +ViewModel key is calculated against Key and/or Qualifier +::: + ## Activity Shared ViewModel One ViewModel instance can be shared between Fragments and their host Activity. @@ -175,6 +179,10 @@ class NavFragment : Fragment() { } ``` +## ViewModel Scope API + +see all API to be used for ViewModel and Scopes: [ViewModel Scope](/docs/reference/koin-android/scope.md#viewmodel-scope-since-354) + ## ViewModel Generic API Koin provides some "under the hood" API to directly tweak your ViewModel instance. The available functions are `viewModelForClass` for `ComponentActivity` and `Fragment`: From 7bfac0b1da7d6fde88275aa9a1bbf7e00c62d778 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 18:31:54 +0100 Subject: [PATCH 72/77] fix docs & tests --- docs/reference/koin-android/scope.md | 2 +- examples/gradle/versions.gradle | 4 +++- examples/sample-desktop-compose/build.gradle.kts | 5 +++-- projects/gradle.properties | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index ecb3a4749..b657d0392 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -174,7 +174,7 @@ If you ViewModel can't get access to a dependency, check in which scope it has b :::note -If you _really_ need to leak a dependency from outside a ViewModel scope, you can use "injected parameters" to pass some objects to your ViewModel. +If you _really_ need to bridge a dependency from outside a ViewModel scope, you can use "injected parameters" to pass some objects to your ViewModel. ::: `ScopeViewModel` is a new class to help work on ViewModel scope. This handle ViewModel's scope creation, and provide `scope` property to allow inject with `by scope.inject()`: diff --git a/examples/gradle/versions.gradle b/examples/gradle/versions.gradle index b4bb44c76..edb1b8d3f 100644 --- a/examples/gradle/versions.gradle +++ b/examples/gradle/versions.gradle @@ -2,8 +2,10 @@ ext { // Kotlin kotlin_version = '1.9.21' // Koin Versions - koin_version = '3.5.4-rc-1' + koin_version = '3.5.4-RC-1' koin_android_version = koin_version + koin_compose_version = "1.1.3-RC-1" + coroutines_version = "1.7.3" ktor_version = "2.3.7" // Compose diff --git a/examples/sample-desktop-compose/build.gradle.kts b/examples/sample-desktop-compose/build.gradle.kts index 986c5b913..f8a070ef0 100755 --- a/examples/sample-desktop-compose/build.gradle.kts +++ b/examples/sample-desktop-compose/build.gradle.kts @@ -7,11 +7,12 @@ plugins { repositories { mavenCentral() + mavenLocal() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() } -val koin_version : String by project +val koin_compose_version : String by project dependencies { // Note, if you develop a library, you should use compose.desktop.common. @@ -19,7 +20,7 @@ dependencies { // (in a separate module for demo project and in testMain). // With compose.desktop.common you will also lose @Preview functionality implementation(compose.desktop.currentOs) - implementation("io.insert-koin:koin-compose:$koin_version") + implementation("io.insert-koin:koin-compose:$koin_compose_version") } compose.desktop { diff --git a/projects/gradle.properties b/projects/gradle.properties index c754d2c3b..06aed45c5 100644 --- a/projects/gradle.properties +++ b/projects/gradle.properties @@ -8,8 +8,8 @@ org.gradle.parallel=true kotlin.code.style=official #Koin -koinVersion=3.5.4-rc-1 -koinComposeVersion=1.1.3-rc-1 +koinVersion=3.5.4-RC-1 +koinComposeVersion=1.1.3-RC-1 #Compose composeCompiler=1.5.7 From dc948544c5e303e9633bb9f6720d8b14db50991c Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 18:41:19 +0100 Subject: [PATCH 73/77] update doc --- docs/reference/koin-android/scope.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index b657d0392..554bc4586 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -216,6 +216,24 @@ class MyActivity : AppCompatActivity() { Once your ViewModel is created, all associated dependencies from within this scope can be created and injected. +To implement manually your ViewModel scope without `ScopeViewModel` class proceed as follow: + +```kotlin +class MyScopeViewModel : ViewModel(), KoinScopeComponent { + + override val scope: Scope = createScope(this) + + // inject your dependency + val session by scope.inject() + + // clear scope + override fun onCleared() { + super.onCleared() + scope.close() + } +} +``` + ## Scope Links Scope links allow to share instances between components with custom scopes. From e1b50a70516a7ab8ac643470b24c0eb379f5a19c Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 18:50:41 +0100 Subject: [PATCH 74/77] Add information about wrapping up around ClosedScopeException case. Fix #1773 --- docs/reference/koin-compose/compose.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/reference/koin-compose/compose.md b/docs/reference/koin-compose/compose.md index bcdad7b54..68d6aa22f 100644 --- a/docs/reference/koin-compose/compose.md +++ b/docs/reference/koin-compose/compose.md @@ -32,12 +32,16 @@ fun App() { } ``` -:::info +:::note Difference between `KoinAndroidContext` and `KoinContext`: - `KoinAndroidContext` is looking into current Android app context for Koin instance - `KoinContext` is looking into current GlobalContext for Koin instances ::: +:::info +If you get some `ClosedScopeException` from a Composable, either use `KoinContext` on your Composable or ensure to have proper Koin start configuration [with Android context](/docs/reference/koin-android/start.md#from-your-application-class) +::: + ### Compose Preview with Koin The `KoinApplication` function is also interesting to start dedicated context for preview. This can be also used to help with Compose preview: From 6f52ed5c4d22386dc9eee41b6755a44c8fb856c9 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Mon, 4 Mar 2024 19:20:51 +0100 Subject: [PATCH 75/77] version 3.5.4-RC1 --- examples/gradle/versions.gradle | 4 ++-- projects/gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/gradle/versions.gradle b/examples/gradle/versions.gradle index edb1b8d3f..a73946b26 100644 --- a/examples/gradle/versions.gradle +++ b/examples/gradle/versions.gradle @@ -2,9 +2,9 @@ ext { // Kotlin kotlin_version = '1.9.21' // Koin Versions - koin_version = '3.5.4-RC-1' + koin_version = '3.5.4-RC1' koin_android_version = koin_version - koin_compose_version = "1.1.3-RC-1" + koin_compose_version = "1.1.3-RC1" coroutines_version = "1.7.3" ktor_version = "2.3.7" diff --git a/projects/gradle.properties b/projects/gradle.properties index 06aed45c5..a41e7b59d 100644 --- a/projects/gradle.properties +++ b/projects/gradle.properties @@ -8,8 +8,8 @@ org.gradle.parallel=true kotlin.code.style=official #Koin -koinVersion=3.5.4-RC-1 -koinComposeVersion=1.1.3-RC-1 +koinVersion=3.5.4-RC1 +koinComposeVersion=1.1.3-RC1 #Compose composeCompiler=1.5.7 From 426c4f4eb7adcaa8fd3cfd5d15361887c7a9910e Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Tue, 5 Mar 2024 07:49:54 +0100 Subject: [PATCH 76/77] Add ViewModel scope warnings &. deprecate API where it can use scope directly --- docs/reference/koin-android/scope.md | 7 +++---- .../java/org/koin/android/compat/GetViewModelCompat.kt | 1 + .../main/java/org/koin/androidx/viewmodel/GetViewModel.kt | 2 +- .../koin/androidx/viewmodel/ext/android/ViewModelLazy.kt | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/reference/koin-android/scope.md b/docs/reference/koin-android/scope.md index 554bc4586..52b21a024 100644 --- a/docs/reference/koin-android/scope.md +++ b/docs/reference/koin-android/scope.md @@ -168,13 +168,12 @@ If you try to access Scope from `onDestroy()` function, scope will be already cl ViewModel is only created against root scope to avoid any leaking (leaking Activity or Fragment ...). This guard for the visibility problem, where ViewModel could have access to incompatible scopes. -:::note -If you ViewModel can't get access to a dependency, check in which scope it has been declared. +:::warn +ViewModel can't access to Activity or Fragment scope. Why? Because ViewModel is lasting long than Activity and Fragment, and then it would leak dependencies outside of proper scopes. ::: - :::note -If you _really_ need to bridge a dependency from outside a ViewModel scope, you can use "injected parameters" to pass some objects to your ViewModel. +If you _really_ need to bridge a dependency from outside a ViewModel scope, you can use "injected parameters" to pass some objects to your ViewModel: `viewModel { p -> }` ::: `ScopeViewModel` is a new class to help work on ViewModel scope. This handle ViewModel's scope creation, and provide `scope` property to allow inject with `by scope.inject()`: diff --git a/projects/android/koin-android-compat/src/main/java/org/koin/android/compat/GetViewModelCompat.kt b/projects/android/koin-android-compat/src/main/java/org/koin/android/compat/GetViewModelCompat.kt index 738e275bd..01dc06f0f 100644 --- a/projects/android/koin-android-compat/src/main/java/org/koin/android/compat/GetViewModelCompat.kt +++ b/projects/android/koin-android-compat/src/main/java/org/koin/android/compat/GetViewModelCompat.kt @@ -27,6 +27,7 @@ import org.koin.core.scope.Scope import kotlin.reflect.KClass @OptIn(KoinInternalApi::class) +@Deprecated("scope is not used for ViewModel creation. This will fallback to root scope.") @KoinInternalApi fun resolveViewModelCompat( vmClass: Class, diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt index 2fbe5f51b..c5725d985 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt @@ -26,7 +26,7 @@ import kotlin.reflect.KClass * @param parameters - for instance building injection */ @KoinInternalApi -@Deprecated("scope is not used for ViewModel creation") +@Deprecated("scope is not used for ViewModel creation. This will fallback to root scope.") fun resolveViewModel( vmClass: KClass, viewModelStore: ViewModelStore, diff --git a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/ViewModelLazy.kt b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/ViewModelLazy.kt index 56350c0d2..f1619491a 100644 --- a/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/ViewModelLazy.kt +++ b/projects/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/ViewModelLazy.kt @@ -68,6 +68,7 @@ fun Fragment.viewModelForClass( } @OptIn(KoinInternalApi::class) +@Deprecated("scope is not used for ViewModel creation. This will fallback to root scope.") @MainThread fun getLazyViewModelForClass( clazz: KClass, From 6cf3bed303f34947fd9269b6b5281c39a782d0e5 Mon Sep 17 00:00:00 2001 From: Arnaud Giuliani Date: Tue, 5 Mar 2024 07:51:07 +0100 Subject: [PATCH 77/77] fix back version to 3.6.0-Beta1 --- projects/gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/gradle.properties b/projects/gradle.properties index a41e7b59d..2a20a43d7 100644 --- a/projects/gradle.properties +++ b/projects/gradle.properties @@ -8,8 +8,8 @@ org.gradle.parallel=true kotlin.code.style=official #Koin -koinVersion=3.5.4-RC1 -koinComposeVersion=1.1.3-RC1 +koinVersion=3.6.0-Beta1 +koinComposeVersion=1.2.0-Beta1 #Compose composeCompiler=1.5.7