├── android
├── src
│ ├── main
│ │ ├── res
│ │ │ └── .gitcreate
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── rewedigital
│ │ │ └── katana
│ │ │ └── android
│ │ │ ├── AndroidKatanaLogger.kt
│ │ │ ├── fragment
│ │ │ ├── KatanaFragment.kt
│ │ │ └── KatanaFragmentDelegate.kt
│ │ │ ├── environment
│ │ │ └── AndroidEnvironmentContext.kt
│ │ │ └── modules
│ │ │ └── AndroidModules.kt
│ └── test
│ │ └── kotlin
│ │ └── .gitcreate
├── proguard-consumer-rules.pro
├── build.gradle.kts
└── README.md
├── androidx-fragment
├── src
│ └── main
│ │ ├── res
│ │ └── .gitcreate
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── org
│ │ └── rewedigital
│ │ └── katana
│ │ └── androidx
│ │ └── fragment
│ │ └── KatanaFragmentFactory.kt
├── build.gradle.kts
└── README.md
├── androidx-viewmodel
├── src
│ ├── main
│ │ ├── res
│ │ │ └── .gitcreate
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── rewedigital
│ │ │ └── katana
│ │ │ └── androidx
│ │ │ └── viewmodel
│ │ │ ├── internal
│ │ │ └── Utils.kt
│ │ │ └── ViewModel.kt
│ └── test
│ │ └── kotlin
│ │ └── .gitcreate
├── proguard-consumer-rules.pro
├── build.gradle.kts
└── README.md
├── androidx-viewmodel-savedstate
├── src
│ ├── main
│ │ ├── res
│ │ │ └── .gitcreate
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── rewedigital
│ │ │ └── katana
│ │ │ └── androidx
│ │ │ └── viewmodel
│ │ │ └── savedstate
│ │ │ └── ViewModelSavedState.kt
│ └── test
│ │ └── kotlin
│ │ └── .gitcreate
├── proguard-consumer-rules.pro
├── build.gradle.kts
└── README.md
├── proguard-rules.pro
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── android-example
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── main_strings.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── layout
│ │ │ │ ├── fragment_first.xml
│ │ │ │ ├── dialog_remote.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_fragment.xml
│ │ │ │ └── fragment_second.xml
│ │ │ └── drawable
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── kotlin
│ │ │ └── org
│ │ │ │ └── rewedigital
│ │ │ │ └── katana
│ │ │ │ └── android
│ │ │ │ └── example
│ │ │ │ ├── main
│ │ │ │ ├── model
│ │ │ │ │ ├── ViewButton.kt
│ │ │ │ │ └── Button.kt
│ │ │ │ ├── view
│ │ │ │ │ ├── MainView.kt
│ │ │ │ │ └── MainActivity.kt
│ │ │ │ ├── navigator
│ │ │ │ │ └── MainNavigator.kt
│ │ │ │ ├── Modules.kt
│ │ │ │ ├── mapper
│ │ │ │ │ └── ButtonMapper.kt
│ │ │ │ ├── repository
│ │ │ │ │ └── ButtonRepository.kt
│ │ │ │ ├── interactor
│ │ │ │ │ └── MainInteractor.kt
│ │ │ │ ├── presenter
│ │ │ │ │ └── MainPresenter.kt
│ │ │ │ └── MainModule.kt
│ │ │ │ ├── fragment
│ │ │ │ ├── inject
│ │ │ │ │ └── Container.kt
│ │ │ │ ├── FragmentActivityModule.kt
│ │ │ │ ├── FirstFragmentModule.kt
│ │ │ │ ├── model
│ │ │ │ │ └── SecondFragmentViewModel.kt
│ │ │ │ ├── SecondFragmentModule.kt
│ │ │ │ ├── FragmentFactoryModule.kt
│ │ │ │ └── view
│ │ │ │ │ ├── FragmentActivity.kt
│ │ │ │ │ ├── FirstFragment.kt
│ │ │ │ │ └── SecondFragment.kt
│ │ │ │ ├── remote
│ │ │ │ ├── model
│ │ │ │ │ └── Post.kt
│ │ │ │ ├── JsonPlaceholderApi.kt
│ │ │ │ ├── JsonPlaceholderRepository.kt
│ │ │ │ └── RemoteModule.kt
│ │ │ │ ├── inject
│ │ │ │ └── AndroidModule.kt
│ │ │ │ └── KatanaApp.kt
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── kotlin
│ │ └── org
│ │ └── rewedigital
│ │ └── katana
│ │ └── android
│ │ └── example
│ │ ├── remote
│ │ ├── JsonPlaceholderApiErrorMock.kt
│ │ ├── TestJsonPlaceholderRepository.kt
│ │ └── JsonPlaceholderApiSuccessMock.kt
│ │ └── main
│ │ ├── TestModules.kt
│ │ └── MainEspressoTest.kt
├── README.md
├── build.gradle.kts
└── etc
│ └── launcher_icon.svg
├── core
├── src
│ ├── main
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── rewedigital
│ │ │ └── katana
│ │ │ ├── Aliases.kt
│ │ │ ├── dsl
│ │ │ ├── ModuleDslMarker.kt
│ │ │ ├── internal
│ │ │ │ └── Internal.kt
│ │ │ ├── ProviderDsl.kt
│ │ │ └── Dsl.kt
│ │ │ ├── environment
│ │ │ ├── EnvironmentContext.kt
│ │ │ ├── MapFactory.kt
│ │ │ └── DefaultEnvironmentContext.kt
│ │ │ ├── package.md
│ │ │ ├── internal
│ │ │ └── Logger.kt
│ │ │ ├── Exceptions.kt
│ │ │ ├── Declaration.kt
│ │ │ ├── BindingContext.kt
│ │ │ ├── Provider.kt
│ │ │ ├── Katana.kt
│ │ │ ├── Key.kt
│ │ │ ├── KatanaTrait.kt
│ │ │ └── Module.kt
│ └── test
│ │ └── kotlin
│ │ └── org
│ │ └── rewedigital
│ │ └── katana
│ │ ├── TestClasses.kt
│ │ ├── TestEnvironmentContext.kt
│ │ ├── ComponentTests.kt
│ │ ├── AliasTests.kt
│ │ ├── TypeErasureTests.kt
│ │ ├── KatanaTraitTests.kt
│ │ ├── ComponentBuilderTests.kt
│ │ ├── NamedInjectionTests.kt
│ │ ├── LoggerTests.kt
│ │ ├── ModuleIncludesTest.kt
│ │ ├── OverrideTests.kt
│ │ ├── ComponentDependsOnTests.kt
│ │ └── SetTests.kt
└── build.gradle.kts
├── speed-comparison
├── src
│ └── main
│ │ └── kotlin
│ │ └── org
│ │ └── rewedigital
│ │ └── katana
│ │ └── comparison
│ │ ├── Subject.kt
│ │ ├── Dependencies.kt
│ │ ├── KoinSubject.kt
│ │ ├── KodeinSubject.kt
│ │ ├── KatanaSubject.kt
│ │ └── Comparison.kt
├── build.gradle.kts
└── README.md
├── gradle.properties
├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.md
└── workflows
│ └── build.yml
├── settings.gradle.kts
├── .idea
├── dictionaries
│ └── sven.xml
└── runConfigurations
│ ├── Android_Example_Tests.xml
│ ├── Android_Example.xml
│ └── Android_Example__Fragment_.xml
├── LICENSE
├── gradlew.bat
├── README.md
├── gradlew
├── Getting Started.md
└── CHANGELOG.md
/android/src/main/res/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/android/src/test/kotlin/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/androidx-fragment/src/main/res/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/androidx-viewmodel/src/main/res/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/androidx-viewmodel/src/test/kotlin/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/androidx-viewmodel-savedstate/src/main/res/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/androidx-viewmodel-savedstate/src/test/kotlin/.gitcreate:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -dontobfuscate
2 | -keep class org.rewedigital.katana.** { *; }
3 |
--------------------------------------------------------------------------------
/android/proguard-consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Currently Katana does not require any specific ProGuard configuration
2 |
--------------------------------------------------------------------------------
/androidx-viewmodel/proguard-consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Currently Katana does not require any specific ProGuard configuration
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/androidx-viewmodel-savedstate/proguard-consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Currently Katana does not require any specific ProGuard configuration
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .idea
3 | !.idea/dictionaries/
4 | !.idea/runConfigurations/
5 | *.iml
6 | build
7 | out
8 | local.properties
9 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android-example/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/androidx-fragment/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/androidx-viewmodel/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/Aliases.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | internal typealias Declarations = Map>
4 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/dsl/ModuleDslMarker.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.dsl
2 |
3 | @DslMarker
4 | annotation class ModuleDslMarker
5 |
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidx-viewmodel-savedstate/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rewe-digital/katana/HEAD/android-example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android-example/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/environment/EnvironmentContext.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.environment
2 |
3 | interface EnvironmentContext {
4 |
5 | fun mapFactory(): MapFactory
6 | }
7 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/environment/MapFactory.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.environment
2 |
3 | interface MapFactory {
4 |
5 | fun create(initialCapacity: Int? = null): MutableMap
6 | }
7 |
--------------------------------------------------------------------------------
/speed-comparison/src/main/kotlin/org/rewedigital/katana/comparison/Subject.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.comparison
2 |
3 | interface Subject {
4 |
5 | fun setup()
6 |
7 | fun execute()
8 |
9 | fun shutdown()
10 | }
11 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/model/ViewButton.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.model
2 |
3 | data class ViewButton(
4 | val id: String,
5 | val label: String,
6 | val message: String
7 | )
8 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/inject/Container.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment.inject
2 |
3 | data class Container(
4 | val activityDependency: String,
5 | val fragmentDependency: String
6 | )
7 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/remote/model/Post.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote.model
2 |
3 | data class Post(
4 | val userId: Int,
5 | val id: Int,
6 | val title: String,
7 | val body: String
8 | )
9 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | kotlin.code.style=official
4 | kotlin.incremental=true
5 | kotlin.parallel.tasks.in.project=true
6 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" -XX:MaxMetaspaceSize=2g
7 | org.gradle.parallel=true
8 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/model/Button.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.model
2 |
3 | import androidx.annotation.StringRes
4 |
5 | data class Button(
6 | val id: String,
7 | @StringRes val labelResId: Int,
8 | @StringRes val messageResId: Int
9 | )
10 |
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android-example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android-example/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Katana Android Example
4 | Fragment example
5 | First fragment %1$s %2$s
6 | Second fragment %1$s %2$s
7 |
8 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/package.md:
--------------------------------------------------------------------------------
1 | # Package org.rewedigital.katana
2 |
3 | ## Names
4 |
5 | Names provided for dependencies are of type `Any`. Any reference that represents a unique identity / equality can be
6 | used as a name. That includes `String` constants, Kotlin `object`s, enum classes or custom (data) classes that implement
7 | `equals()` / `hashCode()` correctly.
8 |
--------------------------------------------------------------------------------
/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `base-android-plugin`
3 | }
4 |
5 | configureBase(
6 | artifactName = "katana-android",
7 | sourcePath = android.sourceSets["main"].java.srcDirs,
8 | componentName = "release"
9 | )
10 |
11 | dependencies {
12 | api(project(":core"))
13 | api(Dependencies.androidXCollection)
14 | api(Dependencies.androidXFragment)
15 | }
16 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/view/MainView.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.view
2 |
3 | interface MainView {
4 |
5 | fun addButton(id: String, label: String)
6 |
7 | fun showToast(message: String)
8 |
9 | fun showDialog()
10 |
11 | fun setDialogResult(result: String)
12 |
13 | fun dismissDialog()
14 | }
15 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/remote/JsonPlaceholderApi.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote
2 |
3 | import kotlinx.coroutines.Deferred
4 | import org.rewedigital.katana.android.example.remote.model.Post
5 | import retrofit2.http.GET
6 |
7 | interface JsonPlaceholderApi {
8 |
9 | @GET("posts")
10 | fun posts(): Deferred>
11 | }
12 |
--------------------------------------------------------------------------------
/androidx-fragment/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `base-android-plugin`
3 | }
4 |
5 | configureBase(
6 | artifactName = "katana-androidx-fragment",
7 | sourcePath = android.sourceSets["main"].java.srcDirs,
8 | componentName = "release"
9 | )
10 |
11 | dependencies {
12 | api(project(":core"))
13 | api(Dependencies.androidXCollection)
14 | api(Dependencies.androidXFragment)
15 | }
16 |
--------------------------------------------------------------------------------
/androidx-viewmodel/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `base-android-plugin`
3 | }
4 |
5 | configureBase(
6 | artifactName = "katana-androidx-viewmodel",
7 | sourcePath = android.sourceSets["main"].java.srcDirs,
8 | componentName = "release"
9 | )
10 |
11 | dependencies {
12 | api(project(":core"))
13 | api(Dependencies.androidXFragment)
14 | api(Dependencies.androidXLifecycleViewModel)
15 | }
16 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/FragmentActivityModule.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment
2 |
3 | import org.rewedigital.katana.Module
4 | import org.rewedigital.katana.dsl.factory
5 |
6 | const val SOME_DEPENDENCY = "SOME_DEPENDENCY"
7 |
8 | val FragmentActivityModule = Module {
9 |
10 | factory(name = SOME_DEPENDENCY) { "SOME_DEPENDENCY" }
11 | }
12 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/navigator/MainNavigator.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.navigator
2 |
3 | import android.app.Activity
4 |
5 | interface MainNavigator {
6 |
7 | fun exit()
8 | }
9 |
10 | class MainNavigatorImpl(private val activity: Activity) : MainNavigator {
11 |
12 | override fun exit() {
13 | activity.finish()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/FirstFragmentModule.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment
2 |
3 | import org.rewedigital.katana.Module
4 | import org.rewedigital.katana.dsl.factory
5 |
6 | const val FRAGMENT_DEPENDENCY1 = "FRAGMENT_DEPENDENCY1"
7 |
8 | val FirstFragmentModule = Module {
9 |
10 | factory(name = FRAGMENT_DEPENDENCY1) { "FRAGMENT_DEPENDENCY1" }
11 | }
12 |
--------------------------------------------------------------------------------
/android-example/src/androidTest/kotlin/org/rewedigital/katana/android/example/remote/JsonPlaceholderApiErrorMock.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote
2 |
3 | import kotlinx.coroutines.Deferred
4 | import org.rewedigital.katana.android.example.remote.model.Post
5 |
6 | class JsonPlaceholderApiErrorMock : JsonPlaceholderApi {
7 |
8 | override fun posts(): Deferred> {
9 | throw IllegalArgumentException()
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/core/src/test/kotlin/org/rewedigital/katana/TestClasses.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("unused")
2 |
3 | package org.rewedigital.katana
4 |
5 | interface MyComponent
6 |
7 | class MyComponentA : MyComponent
8 |
9 | class MyComponentB(val value: T) : MyComponent
10 |
11 | class MyComponentC(
12 | val value: A,
13 | val value2: B
14 | ) : MyComponent
15 |
16 | class A(val b: B)
17 |
18 | class B(val a: A)
19 |
20 | class A2(val b2: Lazy)
21 |
22 | class B2(val a2: A2)
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: svenjacobs
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Expected behavior**
14 | A clear and concise description of what you expected to happen.
15 |
16 | **Example project**
17 | If possible, add minimal example project reproducing the issue.
18 |
19 | **Versions**
20 | Versions of libraries used (Kotlin, Katana, etc.)
21 |
--------------------------------------------------------------------------------
/androidx-viewmodel-savedstate/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `base-android-plugin`
3 | }
4 |
5 | configureBase(
6 | artifactName = "katana-androidx-viewmodel-savedstate",
7 | sourcePath = android.sourceSets["main"].java.srcDirs,
8 | componentName = "release"
9 | )
10 |
11 | dependencies {
12 | api(project(":core"))
13 | api(project(":androidx-viewmodel")) {
14 | exclude(group = "androidx.lifecycle", module = "lifecycle-viewmodel")
15 | }
16 | api(Dependencies.androidXLifecycleViewModelSavedState)
17 | }
18 |
--------------------------------------------------------------------------------
/speed-comparison/src/main/kotlin/org/rewedigital/katana/comparison/Dependencies.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.comparison
2 |
3 | class MySingleton
4 |
5 | interface MyDependency {
6 |
7 | fun execute()
8 | }
9 |
10 | @Suppress("unused")
11 | class MyDependencyImpl(private val mySingleton: MySingleton) :
12 | MyDependency {
13 |
14 | override fun execute() {
15 | }
16 | }
17 |
18 | @Suppress("unused")
19 | class MyDependency2(private val mySingleton: MySingleton) :
20 | MyDependency {
21 |
22 | override fun execute() {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/android-example/README.md:
--------------------------------------------------------------------------------
1 | Demo Android application of the Katana dependency injection library.
2 |
3 | This demo application showcases the usage of Katana on Android. It also demonstrates how UI
4 | ([Espresso](https://developer.android.com/training/testing/espresso/)) tests can be performed along
5 | with Katana and mocking. Please see `MainEspressoTest`.
6 |
7 | Additionally to dependency injection the demo uses the
8 | [Model-view-presenter](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter)
9 | (MVP) pattern to better showcase the capabilities of Katana.
10 |
--------------------------------------------------------------------------------
/android-example/src/main/res/layout/fragment_first.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/environment/DefaultEnvironmentContext.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.environment
2 |
3 | object DefaultEnvironmentContext : EnvironmentContext {
4 |
5 | private class DefaultMapFactory : MapFactory {
6 |
7 | override fun create(initialCapacity: Int?): MutableMap =
8 | if (initialCapacity == null) {
9 | HashMap()
10 | } else {
11 | HashMap(initialCapacity)
12 | }
13 | }
14 |
15 | override fun mapFactory(): MapFactory = DefaultMapFactory()
16 | }
17 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | include(
2 | "core",
3 | "android",
4 | "androidx-fragment",
5 | "androidx-viewmodel",
6 | "androidx-viewmodel-savedstate",
7 |
8 | "speed-comparison",
9 | "android-example"
10 | )
11 |
12 | pluginManagement {
13 | repositories {
14 | gradlePluginPortal()
15 | google()
16 | }
17 | resolutionStrategy {
18 | eachPlugin {
19 | if (requested.id.id == "com.android.library") {
20 | useModule("com.android.tools.build:gradle:${requested.version}")
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/androidx-viewmodel/src/main/kotlin/org/rewedigital/katana/androidx/viewmodel/internal/Utils.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.androidx.viewmodel.internal
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | /**
6 | * Returns name for [ViewModel] dependency binding.
7 | *
8 | * The binding under the returned name should only be used by these ViewModel extensions and not accessed
9 | * outside of this scope via `get()` or `inject()` for instance.
10 | */
11 | fun viewModelName(modelClass: Class, key: String?) =
12 | "ViewModel\$\$${modelClass.name}\$\$${key ?: "DEFAULT_KEY"}"
13 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/model/SecondFragmentViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment.model
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 | import androidx.lifecycle.ViewModel
5 |
6 | data class SecondFragmentViewModel(
7 | private val state: SavedStateHandle
8 | ) : ViewModel() {
9 |
10 | var message: String?
11 | get() = state.get(KEY_MESSAGE)
12 | set(value) {
13 | state.set(KEY_MESSAGE, value)
14 | }
15 |
16 | private companion object {
17 | private const val KEY_MESSAGE = "MESSAGE"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/android-example/src/main/res/values/main_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Remote
4 | Bye
5 | Button 1
6 | You clicked the first button
7 | Button 2
8 | You clicked the second button
9 | Turn your device. There should be no memory leak after the orientation change!
10 |
11 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/remote/JsonPlaceholderRepository.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.withContext
5 | import org.rewedigital.katana.android.example.remote.model.Post
6 |
7 | interface JsonPlaceholderRepository {
8 |
9 | suspend fun posts(): List
10 | }
11 |
12 | class JsonPlaceholderRepositoryImpl(
13 | private val api: JsonPlaceholderApi
14 | ) : JsonPlaceholderRepository {
15 |
16 | override suspend fun posts() =
17 | withContext(Dispatchers.IO) {
18 | api.posts().await()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/internal/Logger.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.internal
2 |
3 | import org.rewedigital.katana.Katana
4 |
5 | internal object Logger {
6 |
7 | fun debug(msg: () -> String) {
8 | Katana.logger?.debug(msg())
9 | }
10 |
11 | fun info(msg: () -> String) {
12 | Katana.logger?.info(msg())
13 | }
14 |
15 | fun warn(msg: () -> String) {
16 | Katana.logger?.warn(msg())
17 | }
18 |
19 | fun error(msgAndThrowable: () -> Pair) {
20 | Katana.logger?.let { logger ->
21 | val pair = msgAndThrowable()
22 | logger.error(pair.first, pair.second)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/Modules.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main
2 |
3 | import org.rewedigital.katana.android.example.remote.ApiModule
4 | import org.rewedigital.katana.android.example.remote.MoshiModule
5 | import org.rewedigital.katana.android.example.remote.RepositoryModule
6 | import org.rewedigital.katana.android.example.remote.RetrofitModule
7 |
8 | object Modules {
9 |
10 | // Additional modules for main feature are placed here.
11 | // We can replace this list during UI tests with mock modules.
12 | var modules = listOf(
13 | MoshiModule,
14 | RetrofitModule,
15 | ApiModule,
16 | RepositoryModule
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/mapper/ButtonMapper.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.mapper
2 |
3 | import android.content.Context
4 | import org.rewedigital.katana.android.example.main.model.Button
5 | import org.rewedigital.katana.android.example.main.model.ViewButton
6 |
7 | interface ButtonMapper {
8 |
9 | fun map(button: Button): ViewButton
10 | }
11 |
12 | class ButtonMapperImpl(private val context: Context) : ButtonMapper {
13 |
14 | override fun map(button: Button) =
15 | ViewButton(
16 | id = button.id,
17 | label = context.getString(button.labelResId),
18 | message = context.getString(button.messageResId)
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/Exceptions.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | open class KatanaException(message: String, throwable: Throwable? = null) : RuntimeException(message, throwable)
4 |
5 | open class ComponentException(message: String) : KatanaException(message)
6 |
7 | class ComponentNotInitializedException(message: String) : ComponentException(message)
8 |
9 | class InjectionException(message: String) : KatanaException(message)
10 |
11 | class OverrideException(message: String) : KatanaException(message) {
12 | constructor(override: String, existing: String) : this("$override would override $existing")
13 | }
14 |
15 | class InstanceCreationException(message: String, cause: Throwable) : KatanaException(message, cause)
16 |
--------------------------------------------------------------------------------
/core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | import org.jetbrains.dokka.gradle.DokkaTask
4 |
5 | plugins {
6 | kotlin("jvm")
7 | }
8 |
9 | configureBase(
10 | artifactName = "katana-core",
11 | sourcePath = sourceSets["main"].allSource,
12 | componentName = "java"
13 | )
14 |
15 | tasks.withType(DokkaTask::class) {
16 | dokkaSourceSets {
17 | configureEach {
18 | includes.from("src/main/kotlin/org/rewedigital/katana/package.md")
19 | }
20 | }
21 | }
22 |
23 | val jacoco = tasks.withType {
24 | reports {
25 | xml.isEnabled = true
26 | html.isEnabled = false
27 | csv.isEnabled = false
28 | }
29 | }
30 | tasks.getByName("check").dependsOn(jacoco)
31 |
--------------------------------------------------------------------------------
/.idea/dictionaries/sven.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | amshove
5 | anko
6 | bintray
7 | constraintlayout
8 | coroutines
9 | dokka
10 | jakewharton
11 | jfrog
12 | katana
13 | kluent
14 | kodein
15 | koin
16 | kotlinx
17 | leakcanary
18 | mannodermaus
19 | moshi
20 | nield
21 | rewedigital
22 | savedstate
23 | spek
24 | spekframework
25 | squareup
26 | viewmodel
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/inject/AndroidModule.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.inject
2 |
3 | import android.content.Context
4 | import android.content.res.Resources
5 | import org.rewedigital.katana.Module
6 | import org.rewedigital.katana.android.modules.APPLICATION_CONTEXT
7 | import org.rewedigital.katana.dsl.factory
8 | import org.rewedigital.katana.dsl.get
9 |
10 | /**
11 | * This module may provide Android specific classes like [Resources],
12 | * [android.content.SharedPreferences], system services etc.
13 | *
14 | * @see org.rewedigital.katana.android.modules.createApplicationModule
15 | */
16 | val AndroidModule = Module {
17 |
18 | factory { get(APPLICATION_CONTEXT).resources }
19 | }
20 |
--------------------------------------------------------------------------------
/android-example/src/androidTest/kotlin/org/rewedigital/katana/android/example/remote/TestJsonPlaceholderRepository.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote
2 |
3 | import androidx.test.espresso.idling.CountingIdlingResource
4 | import org.rewedigital.katana.android.example.remote.model.Post
5 |
6 | class TestJsonPlaceholderRepository(
7 | private val repository: JsonPlaceholderRepository,
8 | private val repositoryIdlingResource: CountingIdlingResource
9 | ) : JsonPlaceholderRepository {
10 |
11 | override suspend fun posts(): List {
12 | repositoryIdlingResource.increment()
13 | try {
14 | return repository.posts()
15 | } finally {
16 | repositoryIdlingResource.decrement()
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/android-example/src/main/res/layout/dialog_remote.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/speed-comparison/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("jvm")
3 | }
4 |
5 | dependencies {
6 | implementation(project(":core"))
7 | implementation("org.nield:kotlin-statistics:1.2.1")
8 | implementation("org.koin:koin-core:2.0.1")
9 | implementation("org.kodein.di:kodein-di-erased-jvm:6.3.3")
10 | }
11 |
12 | val fatJar = task("fatJar", type = Jar::class) {
13 | archiveBaseName.set("${project.name}-fat")
14 | manifest {
15 | attributes["Main-Class"] = "org.rewedigital.katana.comparison.ComparisonKt"
16 | }
17 | from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
18 | with(tasks["jar"] as CopySpec)
19 |
20 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE
21 | }
22 |
23 | tasks {
24 | "build" {
25 | dependsOn(fatJar)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/test/kotlin/org/rewedigital/katana/TestEnvironmentContext.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | import org.rewedigital.katana.environment.EnvironmentContext
4 | import org.rewedigital.katana.environment.MapFactory
5 |
6 | /**
7 | * Ensures a defined order of dependency declarations resulting in stable and predictable tests by configuring Katana
8 | * to use a [LinkedHashMap].
9 | */
10 | object TestEnvironmentContext : EnvironmentContext {
11 |
12 | private class TestMapFactory : MapFactory {
13 |
14 | override fun create(initialCapacity: Int?): MutableMap =
15 | when (initialCapacity) {
16 | null -> LinkedHashMap()
17 | else -> LinkedHashMap(initialCapacity)
18 | }
19 | }
20 |
21 | override fun mapFactory(): MapFactory = TestMapFactory()
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/Declaration.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | /**
4 | * Represents a dependency declaration.
5 | */
6 | @PublishedApi
7 | internal data class Declaration(
8 | val key: Key,
9 | val type: Type,
10 | val moduleId: Int,
11 | val moduleName: String?,
12 | val clazz: Class,
13 | val name: Any?,
14 | val provider: Provider,
15 | val internal: Boolean
16 | ) {
17 |
18 | enum class Type(
19 | val permitsRedeclaration: Boolean = false
20 | ) {
21 | FACTORY,
22 | SINGLETON,
23 | EAGER_SINGLETON,
24 | SET(permitsRedeclaration = true),
25 | CUSTOM
26 | }
27 |
28 | override fun toString() =
29 | "${clazz.name}(type=$type${name?.let { ", name=$it" }.orEmpty()}${moduleName?.let { ", module=$it" }.orEmpty()})"
30 | }
31 |
--------------------------------------------------------------------------------
/androidx-viewmodel/README.md:
--------------------------------------------------------------------------------
1 | # AndroidX ViewModel extensions for Katana
2 |
3 | The extensions declared in this artifact simplify [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel)
4 | injection with Katana. Also see [katana-androidx-viewmodel-savedstate](../androidx-viewmodel-savedstate).
5 |
6 | Create a ViewModel binding inside a module:
7 |
8 | ```kotlin
9 | data class MyViewModel(val someDependency: SomeDependency) : ViewModel()
10 |
11 | Module {
12 |
13 | viewModel { MyViewModel(get()) }
14 | }
15 | ```
16 |
17 | Inject ViewModel in your `Activity` or `Fragment`:
18 |
19 | ```kotlin
20 | class MyFragment : Fragment(),
21 | KatanaTrait {
22 |
23 | override val component = Component(...)
24 |
25 | private val viewModel by viewModel()
26 | }
27 | ```
28 |
--------------------------------------------------------------------------------
/android-example/src/androidTest/kotlin/org/rewedigital/katana/android/example/remote/JsonPlaceholderApiSuccessMock.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.remote
2 |
3 | import kotlinx.coroutines.CompletableDeferred
4 | import kotlinx.coroutines.Deferred
5 | import org.rewedigital.katana.android.example.remote.model.Post
6 |
7 | class JsonPlaceholderApiSuccessMock : JsonPlaceholderApi {
8 |
9 | override fun posts(): Deferred> =
10 | CompletableDeferred(
11 | listOf(
12 | Post(
13 | userId = 1,
14 | id = 1,
15 | title = "Lorem ipsum",
16 | body = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"
17 | )
18 | )
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/SecondFragmentModule.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment
2 |
3 | import org.rewedigital.katana.Module
4 | import org.rewedigital.katana.android.example.fragment.inject.Container
5 | import org.rewedigital.katana.android.example.fragment.model.SecondFragmentViewModel
6 | import org.rewedigital.katana.androidx.viewmodel.savedstate.viewModelSavedState
7 | import org.rewedigital.katana.dsl.factory
8 | import org.rewedigital.katana.dsl.get
9 |
10 | const val FRAGMENT_DEPENDENCY2 = "FRAGMENT_DEPENDENCY2"
11 |
12 | val SecondFragmentModule = Module {
13 |
14 | factory(name = FRAGMENT_DEPENDENCY2) { "FRAGMENT_DEPENDENCY2" }
15 |
16 | factory { Container(get(SOME_DEPENDENCY), get(FRAGMENT_DEPENDENCY2)) }
17 |
18 | viewModelSavedState { state -> SecondFragmentViewModel(state) }
19 | }
20 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/org/rewedigital/katana/android/AndroidKatanaLogger.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android
2 |
3 | import android.util.Log
4 | import org.rewedigital.katana.Katana
5 |
6 | /**
7 | * Android specific [Katana.Logger] implementation.
8 | *
9 | * @see Katana.logger
10 | */
11 | object AndroidKatanaLogger : Katana.Logger {
12 |
13 | private const val TAG = "KATANA"
14 |
15 | override fun debug(msg: String) {
16 | Log.d(TAG, msg)
17 | }
18 |
19 | override fun info(msg: String) {
20 | Log.i(TAG, msg)
21 | }
22 |
23 | override fun warn(msg: String) {
24 | Log.w(TAG, msg)
25 | }
26 |
27 | override fun error(msg: String, throwable: Throwable?) {
28 | if (throwable != null) {
29 | Log.e(TAG, msg, throwable)
30 | } else {
31 | Log.e(TAG, msg)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/fragment/FragmentFactoryModule.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.fragment
2 |
3 | import org.rewedigital.katana.Module
4 | import org.rewedigital.katana.android.example.fragment.view.FirstFragment
5 | import org.rewedigital.katana.android.example.fragment.view.SecondFragment
6 | import org.rewedigital.katana.androidx.fragment.KatanaFragmentFactory
7 | import org.rewedigital.katana.dsl.component
8 | import org.rewedigital.katana.dsl.factory
9 | import org.rewedigital.katana.dsl.singleton
10 |
11 | val FragmentFactoryModule = Module(
12 | name = "FragmentFactoryModule"
13 | ) {
14 |
15 | singleton {
16 | KatanaFragmentFactory(component)
17 | .handlesFragment()
18 | .handlesFragment()
19 | }
20 |
21 | factory { FirstFragment(component) }
22 |
23 | factory { SecondFragment(component) }
24 | }
25 |
--------------------------------------------------------------------------------
/android-example/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/core/src/test/kotlin/org/rewedigital/katana/ComponentTests.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | import org.amshove.kluent.shouldThrow
4 | import org.spekframework.spek2.Spek
5 | import org.spekframework.spek2.style.specification.describe
6 |
7 | object ComponentTests : Spek(
8 | {
9 | describe("Components") {
10 |
11 | it("should throw exception when no modules or parent components were passed") {
12 | val fn = {
13 | Component()
14 | }
15 |
16 | fn shouldThrow ComponentException::class
17 | }
18 |
19 | it("should throw exception when all modules are empty") {
20 | val fn = {
21 | val module1 = Module {
22 | }
23 |
24 | val module2 = Module {
25 | }
26 |
27 | Component(module1, module2)
28 | }
29 |
30 | fn shouldThrow ComponentException::class
31 | }
32 | }
33 | })
34 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/org/rewedigital/katana/BindingContext.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana
2 |
3 | import org.rewedigital.katana.dsl.ModuleDslMarker
4 | import java.util.concurrent.atomic.AtomicInteger
5 |
6 | abstract class BindingContext {
7 | internal abstract val module: Module
8 | internal abstract val key: Key?
9 | internal abstract val increment: Int?
10 | }
11 |
12 | @ModuleDslMarker
13 | class ModuleBindingContext internal constructor(
14 | @PublishedApi override val module: Module
15 | ) : BindingContext() {
16 |
17 | override val key: Key? = null
18 | override val increment: Int? = null
19 | }
20 |
21 | @ModuleDslMarker
22 | @Suppress("unused")
23 | class SetBindingContext @PublishedApi internal constructor(
24 | override val module: Module,
25 | @PublishedApi override val key: Key
26 | ) : BindingContext() {
27 |
28 | override val increment
29 | get() = nextIncrement.getAndIncrement()
30 |
31 | private companion object {
32 | private val nextIncrement = AtomicInteger()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/speed-comparison/src/main/kotlin/org/rewedigital/katana/comparison/KoinSubject.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.comparison
2 |
3 | import org.koin.core.KoinComponent
4 | import org.koin.core.context.startKoin
5 | import org.koin.core.context.stopKoin
6 | import org.koin.core.inject
7 | import org.koin.dsl.bind
8 | import org.koin.dsl.module
9 |
10 | class KoinSubject : Subject, KoinComponent {
11 |
12 | override fun setup() {
13 | val module = module {
14 |
15 | single { MySingleton() }
16 |
17 | factory { MyDependencyImpl(get()) } bind MyDependency::class
18 |
19 | factory { MyDependency2(get()) }
20 | }
21 |
22 | startKoin {
23 | modules(module)
24 | }
25 | }
26 |
27 | override fun execute() {
28 | val dependency: MyDependency by inject()
29 | val dependency2: MyDependency2 by inject()
30 |
31 | dependency.execute()
32 | dependency2.execute()
33 | }
34 |
35 | override fun shutdown() {
36 | stopKoin()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT license (MIT)
2 |
3 | Copyright (c) 2019 REWE Digital GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8 | persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11 | Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
--------------------------------------------------------------------------------
/speed-comparison/src/main/kotlin/org/rewedigital/katana/comparison/KodeinSubject.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.comparison
2 |
3 | import org.kodein.di.Kodein
4 | import org.kodein.di.erased.bind
5 | import org.kodein.di.erased.instance
6 | import org.kodein.di.erased.provider
7 | import org.kodein.di.erased.singleton
8 |
9 | class KodeinSubject : Subject {
10 |
11 | private lateinit var kodein: Kodein
12 |
13 | override fun setup() {
14 | kodein = Kodein {
15 |
16 | bind() with singleton { MySingleton() }
17 |
18 | bind() with provider {
19 | MyDependencyImpl(instance())
20 | }
21 |
22 | bind() with provider {
23 | MyDependency2(instance())
24 | }
25 | }
26 | }
27 |
28 | override fun execute() {
29 | val dependency: MyDependency by kodein.instance()
30 | val dependency2: MyDependency2 by kodein.instance()
31 |
32 | dependency.execute()
33 | dependency2.execute()
34 | }
35 |
36 | override fun shutdown() {
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/speed-comparison/src/main/kotlin/org/rewedigital/katana/comparison/KatanaSubject.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.comparison
2 |
3 | import org.rewedigital.katana.Component
4 | import org.rewedigital.katana.KatanaTrait
5 | import org.rewedigital.katana.Module
6 | import org.rewedigital.katana.dsl.factory
7 | import org.rewedigital.katana.dsl.get
8 | import org.rewedigital.katana.dsl.singleton
9 | import org.rewedigital.katana.inject
10 |
11 | class KatanaSubject : Subject, KatanaTrait {
12 |
13 | override lateinit var component: Component
14 |
15 | override fun setup() {
16 | val module = Module {
17 |
18 | singleton { MySingleton() }
19 |
20 | factory { MyDependencyImpl(get()) }
21 |
22 | factory { MyDependency2(get()) }
23 | }
24 |
25 | component = Component(module)
26 | }
27 |
28 | override fun execute() {
29 | val dependency: MyDependency by inject()
30 | val dependency2: MyDependency2 by inject()
31 |
32 | dependency.execute()
33 | dependency2.execute()
34 | }
35 |
36 | override fun shutdown() {
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/androidx-fragment/README.md:
--------------------------------------------------------------------------------
1 | # Fragment constructor injection with FragmentFactory
2 |
3 | This artifact provides additional support for `androidx.fragment` enabling constructor injection in Fragments with
4 | `KatanaFragmentFactory`.
5 |
6 | ```kotlin
7 | // In a module:
8 |
9 | val module = Module {
10 |
11 | singleton {
12 | KatanaFragmentFactory(component)
13 | .handlesFragment()
14 | .handlesFragment(name = "SecondFragment")
15 | }
16 |
17 | factory { FirstFragment(get()) }
18 |
19 | factory(name = "SecondFragment") { SecondFragment(get(), get()) }
20 | }
21 |
22 | // ... then in an Activity:
23 |
24 | class MyActivity : AppCompatActivity() {
25 |
26 | private val fragmentFactory by applicationComponent.inject()
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | // Must be set **before** super call for Fragment instantiation after orientation change
30 | supportFragmentManager.fragmentFactory = fragmentFactory
31 |
32 | super.onCreate(savedInstanceState)
33 |
34 | // ...
35 | }
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/android-example/src/main/kotlin/org/rewedigital/katana/android/example/main/repository/ButtonRepository.kt:
--------------------------------------------------------------------------------
1 | package org.rewedigital.katana.android.example.main.repository
2 |
3 | import org.rewedigital.katana.android.example.R
4 | import org.rewedigital.katana.android.example.main.model.Button
5 |
6 | interface ButtonRepository {
7 |
8 | fun fetch(): List