Skip to content

Commit

Permalink
Merge pull request #363 from thomaskioko/kotlin-inject-anvil
Browse files Browse the repository at this point in the history
Kotlin-inject-anvil Integration.
  • Loading branch information
thomaskioko authored Dec 5, 2024
2 parents 6dab9e0 + 84e67d5 commit 1502e15
Show file tree
Hide file tree
Showing 171 changed files with 704 additions and 889 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
TvManiac
-------------------------
![Check](https://github.com/c0de-wizard/tv-maniac/actions/workflows/build.yml/badge.svg)
![android](http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat) ![ios](http://img.shields.io/badge/platform-ios-CDCDCD.svg?style=flat)
![Check](https://github.com/thomaskioko/tv-maniac/actions/workflows/ci.yml/badge.svg)
![kmp](https://img.shields.io/badge/multiplatform-%237F52FF.svg?style=for-the-badge&logo=kotlin&logoColor=white)
![compose](https://img.shields.io/badge/jetpack_compose-2bab6b.svg?style=for-the-badge&logo=android&logoColor=white)
![swiftui](https://img.shields.io/badge/swiftui-%23000000.svg?style=for-the-badge&logo=swift&logoColor=white)
[![TvManiac Debug](https://img.shields.io/badge/Debug--Apk-download-green?style=for-the-badge&logo=android)](https://github.com/c0de-wizard/tv-maniac/releases/latest/download/app-debug.apk)

**TvManiac** is a personalized entertainment tracking and recommendation Multiplatform app. By utilizing
Expand Down Expand Up @@ -119,7 +121,7 @@ This is my playground for learning Kotlin Multiplatform. With that said, I'm sur
* [DateTime](https://github.com/Kotlin/kotlinx-datetime) - Date & Time
* [Decompose](https://arkivanov.github.io/Decompose/) - Kotlin Multiplatform library for breaking down your code into lifecycle-aware business logic components (aka BLoC).
* [Kermit](https://kermit.touchlab.co/) - Logging
* [kotlin-inject](https://github.com/evant/kotlin-inject) - Injection library.
* [kotlin-inject-anvil](https://github.com/amzn/kotlin-inject-anvil?tab=readme-ov-file) - Dependency Injection library.
* [Kotlinx Serialization](https://ktor.io/docs/kotlin-serialization.html) - De/Serializing JSON
* [Ktor](https://ktor.io/) - Networking
* [Kotest Assertions](https://kotest.io/docs/assertions/assertions.html) - Testing
Expand Down
8 changes: 4 additions & 4 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dependencies {
implementation(projects.android.ui.seasonDetails)
implementation(projects.android.ui.showDetails)
implementation(projects.android.ui.trailers)
implementation(projects.shared)
implementation(projects.core.base)
implementation(projects.core.util)
implementation(projects.traktAuth.api)
Expand All @@ -38,6 +37,8 @@ dependencies {
implementation(projects.data.requestManager.api)
implementation(projects.data.requestManager.api)
implementation(projects.data.requestManager.implementation)
implementation(projects.data.search.api)
implementation(projects.data.search.implementation)
implementation(projects.data.seasondetails.api)
implementation(projects.data.seasondetails.implementation)
implementation(projects.data.seasons.api)
Expand Down Expand Up @@ -81,8 +82,9 @@ dependencies {

implementation(libs.decompose.decompose)
implementation(libs.decompose.extensions.compose)
implementation(libs.kotlinInject.runtime)
implementation(libs.bundles.kotlinInject)
ksp(libs.kotlinInject.compiler)
ksp(libs.kotlinInject.anvil.compiler)

implementation(libs.androidx.datastore.core)
implementation(libs.androidx.savedstate)
Expand All @@ -94,5 +96,3 @@ dependencies {
implementation(libs.coroutines.core)
implementation(libs.ktor.core)
}

ksp { arg("me.tatarka.inject.generateCompanionExtensions", "true") }
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import androidx.core.view.WindowCompat
import com.thomaskioko.tvmaniac.compose.theme.TvManiacTheme
import com.thomaskioko.tvmaniac.datastore.api.AppTheme
import com.thomaskioko.tvmaniac.inject.ActivityComponent
import com.thomaskioko.tvmaniac.inject.create
import com.thomaskioko.tvmaniac.navigation.ThemeState

class MainActivity : ComponentActivity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import com.thomaskioko.tvmaniac.inject.ApplicationComponent
import com.thomaskioko.tvmaniac.inject.create

class TvManicApplication : Application() {
private val component: ApplicationComponent by unsafeLazy { ApplicationComponent.create(this) }
private val component: ApplicationComponent by unsafeLazy { ApplicationComponent::class.create(this) }

override fun onCreate() {
super.onCreate()
component.initializers.init()
}

fun getApplicationComponent() = component
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.thomaskioko.tvmaniac.initializers

import com.thomaskioko.tvmaniac.core.base.AppInitializer
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import me.tatarka.inject.annotations.Inject
import software.amazon.lastmile.kotlin.inject.anvil.SingleIn

@Inject
@SingleIn(AppScope::class)
class AppInitializers(
private val initializers: Set<AppInitializer>,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,38 @@ package com.thomaskioko.tvmaniac.inject
import androidx.activity.ComponentActivity
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.defaultComponentContext
import com.thomaskioko.tvmaniac.TvManicApplication
import com.thomaskioko.tvmaniac.core.base.annotations.ActivityScope
import com.thomaskioko.tvmaniac.navigation.RootPresenter
import com.thomaskioko.tvmaniac.navigation.di.NavigatorComponent
import com.thomaskioko.tvmaniac.traktauth.api.TraktAuthManager
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthManagerComponent
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.ContributesSubcomponent
import software.amazon.lastmile.kotlin.inject.anvil.SingleIn

@ActivityScope
@Component
abstract class ActivityComponent(
@get:Provides val activity: ComponentActivity,
@get:Provides val componentContext: ComponentContext = activity.defaultComponentContext(),
@Component
val applicationComponent: ApplicationComponent =
ApplicationComponent.create(activity.application),
) : NavigatorComponent, TraktAuthManagerComponent {
abstract val traktAuthManager: TraktAuthManager
abstract val rootPresenter: RootPresenter
@ContributesSubcomponent(ActivityScope::class)
@SingleIn(ActivityScope::class)
interface ActivityComponent {
@Provides
fun provideComponentContext(
activity: ComponentActivity
): ComponentContext = activity.defaultComponentContext()

companion object
val traktAuthManager: TraktAuthManager
val rootPresenter: RootPresenter

@ContributesSubcomponent.Factory(AppScope::class)
interface Factory {
fun createComponent(
activity: ComponentActivity
): ActivityComponent
}

companion object {
fun create(activity: ComponentActivity): ActivityComponent =
(activity.application as TvManicApplication)
.getApplicationComponent()
.activityComponentFactory
.createComponent(activity)
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.thomaskioko.tvmaniac.inject

import android.app.Application
import com.thomaskioko.tvmaniac.core.base.annotations.ApplicationScope
import com.thomaskioko.tvmaniac.initializers.AppInitializers
import com.thomaskioko.tvmaniac.shared.SharedComponent
import com.thomaskioko.tvmaniac.traktauth.implementation.TraktAuthComponent
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.MergeComponent
import software.amazon.lastmile.kotlin.inject.anvil.SingleIn

@Component
@ApplicationScope
@MergeComponent(AppScope::class)
@SingleIn(AppScope::class)
abstract class ApplicationComponent(
@get:Provides val application: Application,
) : SharedComponent(), TraktAuthComponent {
) : ActivityComponent.Factory {
abstract val initializers: AppInitializers
abstract val activityComponentFactory: ActivityComponent.Factory

companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import org.gradle.kotlin.dsl.findByType
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.util.Locale

class KotlinMultiplatformConventionPlugin : Plugin<Project> {
override fun apply(target: Project) = with(target) {
Expand Down Expand Up @@ -88,15 +87,15 @@ class KotlinMultiplatformConventionPlugin : Plugin<Project> {
"androidTestFixtures",
"androidTestFixturesDebug",
"androidTestFixturesRelease",
"androidTestFixturesDemo"
"androidTestFixturesDemo",
).contains(it.name)
}
}
}
}
}

fun Project.addLanguageArgs(vararg args: String){
fun Project.addLanguageArgs(vararg args: String) {
extensions.configure<KotlinMultiplatformExtension> {
sourceSets.all {
languageSettings {
Expand All @@ -112,18 +111,19 @@ private fun Project.addKspDependencyForAllTargets(
dependencyNotation: Any,
) {
val kmpExtension = extensions.getByType<KotlinMultiplatformExtension>()
val kspTargets = kmpExtension.targets.names.map { targetName ->
targetName.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString()
}
}
dependencies {
kmpExtension.targets
kspTargets
.asSequence()
.filter { target ->
// Don't add KSP for common target, only final platforms
target.platformType != KotlinPlatformType.common
.map { target ->
if (target == "Metadata") "CommonMainMetadata" else target
}
.forEach { target ->
add(
"ksp${target.name.replaceFirstChar(Char::uppercaseChar)}$configurationNameSuffix",
dependencyNotation,
)
.forEach { targetConfigSuffix ->
add("ksp${targetConfigSuffix}$configurationNameSuffix", dependencyNotation)
}
}
}
7 changes: 6 additions & 1 deletion core/base/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import com.thomaskioko.tvmaniac.plugins.addKspDependencyForAllTargets
import com.thomaskioko.tvmaniac.plugins.addLanguageArgs

plugins {
alias(libs.plugins.tvmaniac.android.library)
alias(libs.plugins.tvmaniac.multiplatform)
alias(libs.plugins.serialization)
alias(libs.plugins.ksp)
}

kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.coroutines.core)
implementation(libs.decompose.decompose)
implementation(libs.kotlinInject.runtime)
implementation(libs.bundles.kotlinInject)
implementation(libs.ktor.serialization)
}
}
Expand All @@ -22,3 +24,6 @@ android { namespace = "com.thomaskioko.tvmaniac.core.base" }
addLanguageArgs(
"kotlinx.coroutines.InternalCoroutinesApi",
)

addKspDependencyForAllTargets(libs.kotlinInject.compiler)
addKspDependencyForAllTargets(libs.kotlinInject.anvil.compiler)
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
package com.thomaskioko.tvmaniac.core.base.di

import com.thomaskioko.tvmaniac.core.base.annotations.ApplicationScope
import com.thomaskioko.tvmaniac.core.base.model.AppCoroutineDispatchers
import com.thomaskioko.tvmaniac.core.base.model.AppCoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import me.tatarka.inject.annotations.Provides
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.ContributesTo

actual interface BaseComponent {
@ContributesTo(AppScope::class)
interface BaseAndroidComponent {

@ApplicationScope
@Provides
fun provideCoroutineDispatchers(): AppCoroutineDispatchers =
AppCoroutineDispatchers(
io = Dispatchers.IO,
computation = Dispatchers.Default,
main = Dispatchers.Main,
)

@ApplicationScope
@Provides
fun provideCoroutineScope(dispatchers: AppCoroutineDispatchers): AppCoroutineScope =
AppCoroutineScope(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ package com.thomaskioko.tvmaniac.core.base.annotations

import me.tatarka.inject.annotations.Scope

@Scope annotation class ApplicationScope

@Scope annotation class ActivityScope
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
package com.thomaskioko.tvmaniac.core.base.di

expect interface BaseComponent
import com.thomaskioko.tvmaniac.core.base.model.AppCoroutineDispatchers
import kotlinx.coroutines.Dispatchers
import me.tatarka.inject.annotations.Provides
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.ContributesTo

@ContributesTo(AppScope::class)
interface BaseComponent {

@Provides
fun provideCoroutineDispatchers(): AppCoroutineDispatchers =
AppCoroutineDispatchers(
io = Dispatchers.Default,
computation = Dispatchers.Default,
main = Dispatchers.Main,
)
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
package com.thomaskioko.tvmaniac.core.base.di

import com.thomaskioko.tvmaniac.core.base.annotations.ApplicationScope
import com.thomaskioko.tvmaniac.core.base.model.AppCoroutineDispatchers
import com.thomaskioko.tvmaniac.core.base.model.AppCoroutineScope
import com.thomaskioko.tvmaniac.core.base.scope.NsQueueCoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import me.tatarka.inject.annotations.Provides
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.ContributesTo

actual interface BaseComponent {
@ContributesTo(AppScope::class)
interface BaseIosComponent {

@ApplicationScope
@Provides
fun provideCoroutineDispatchers(): AppCoroutineDispatchers =
AppCoroutineDispatchers(
io = Dispatchers.Default,
computation = Dispatchers.Default,
main = Dispatchers.Main,
)

@ApplicationScope
@Provides
fun provideAppCoroutineScope(dispatchers: AppCoroutineDispatchers): AppCoroutineScope =
AppCoroutineScope(
Expand Down

This file was deleted.

7 changes: 6 additions & 1 deletion core/logger/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import com.thomaskioko.tvmaniac.plugins.addKspDependencyForAllTargets

plugins {
alias(libs.plugins.tvmaniac.multiplatform)
alias(libs.plugins.ksp)
Expand All @@ -9,7 +11,10 @@ kotlin {
implementation(projects.core.base)
implementation(libs.kermit)
implementation(libs.napier)
implementation(libs.kotlinInject.runtime)
implementation(libs.bundles.kotlinInject)
}
}
}

addKspDependencyForAllTargets(libs.kotlinInject.compiler)
addKspDependencyForAllTargets(libs.kotlinInject.anvil.compiler)
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import com.thomaskioko.tvmaniac.core.base.AppInitializer
import io.github.aakira.napier.DebugAntilog
import io.github.aakira.napier.Napier
import me.tatarka.inject.annotations.Inject
import software.amazon.lastmile.kotlin.inject.anvil.AppScope
import software.amazon.lastmile.kotlin.inject.anvil.ContributesBinding

@Inject
@ContributesBinding(AppScope::class, multibinding = true)
class LoggingInitializer : AppInitializer {

override fun init() {
Expand Down
Loading

0 comments on commit 1502e15

Please sign in to comment.