diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 9c465615ea..c9c77fe66f 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -3,6 +3,7 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.anvil)
+ alias(libs.plugins.kapt)
id("com.google.firebase.appdistribution") version "3.0.2"
}
@@ -101,16 +102,16 @@ android {
}
}
- kotlin {
- sourceSets.main {
- kotlin.srcDir("build/generated/ksp/main/kotlin")
- }
- sourceSets.test {
- kotlin.srcDir("build/generated/ksp/test/kotlin")
+ applicationVariants.all {
+ kotlin.sourceSets {
+ getByName(name) {
+ kotlin.srcDir("build/generated/ksp/$name/kotlin")
+ }
}
}
}
+
dependencies {
implementation(project(":libraries:designsystem"))
implementation(project(":libraries:matrix"))
@@ -119,6 +120,7 @@ dependencies {
implementation(project(":features:login"))
implementation(project(":features:roomlist"))
implementation(project(":features:messages"))
+ implementation(project(":libraries:daggerscopes"))
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.0")
implementation(libs.compose.destinations)
@@ -128,11 +130,13 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.startup)
implementation(libs.coil)
implementation(libs.timber)
implementation(libs.mavericks.compose)
implementation(libs.dagger)
+ kapt(libs.dagger.compiler)
implementation(libs.showkase)
ksp(libs.showkase.processor)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0a49fe2a4b..b82495751d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/ElementXApplication.kt b/app/src/main/java/io/element/android/x/ElementXApplication.kt
index 715b6c215b..7980a5aea4 100644
--- a/app/src/main/java/io/element/android/x/ElementXApplication.kt
+++ b/app/src/main/java/io/element/android/x/ElementXApplication.kt
@@ -1,32 +1,31 @@
package io.element.android.x
import android.app.Application
-import coil.ImageLoader
-import coil.ImageLoaderFactory
-import com.airbnb.mvrx.Mavericks
+import androidx.startup.AppInitializer
+import io.element.android.x.core.di.DaggerComponentOwner
+import io.element.android.x.di.DaggerAppComponent
+import io.element.android.x.initializer.CoilInitializer
+import io.element.android.x.initializer.MavericksInitializer
+import io.element.android.x.initializer.TimberInitializer
import io.element.android.x.matrix.MatrixInstance
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.plus
-import timber.log.Timber
-class ElementXApplication : Application(), ImageLoaderFactory {
+class ElementXApplication : Application(), DaggerComponentOwner {
+
+ override lateinit var daggerComponent: Any
private val applicationScope = MainScope() + CoroutineName("ElementX Scope")
override fun onCreate() {
super.onCreate()
- Timber.plant(Timber.DebugTree())
+ daggerComponent = DaggerAppComponent.factory().create(this)
MatrixInstance.init(this, applicationScope)
- Mavericks.initialize(this)
+ AppInitializer.getInstance(this).apply {
+ initializeComponent(TimberInitializer::class.java)
+ initializeComponent(CoilInitializer::class.java)
+ initializeComponent(MavericksInitializer::class.java)
+ }
}
-
- override fun newImageLoader(): ImageLoader {
- return ImageLoader
- .Builder(this)
- .components {
- MatrixInstance.getInstance().registerComponents(this)
- }
- .build()
- }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/element/android/x/MainActivity.kt b/app/src/main/java/io/element/android/x/MainActivity.kt
index 68c524d52a..61bd7660cc 100644
--- a/app/src/main/java/io/element/android/x/MainActivity.kt
+++ b/app/src/main/java/io/element/android/x/MainActivity.kt
@@ -32,8 +32,11 @@ import com.google.accompanist.navigation.material.ExperimentalMaterialNavigation
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
import com.ramcosta.composedestinations.animations.rememberAnimatedNavHostEngine
+import com.ramcosta.composedestinations.manualcomposablecalls.animatedComposable
+import com.ramcosta.composedestinations.navigation.dependency
import com.ramcosta.composedestinations.spec.Route
import io.element.android.x.core.compose.OnLifecycleEvent
+import io.element.android.x.core.di.DaggerComponentOwner
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.destinations.OnBoardingScreenNavigationDestination
import kotlinx.coroutines.runBlocking
@@ -147,7 +150,10 @@ class MainActivity : ComponentActivity() {
engine = engine,
navController = navController,
navGraph = NavGraphs.root,
- startRoute = startRoute
+ startRoute = startRoute,
+ dependenciesContainerBuilder = {
+
+ }
)
}
diff --git a/app/src/main/java/io/element/android/x/di/AppBindings.kt b/app/src/main/java/io/element/android/x/di/AppBindings.kt
new file mode 100644
index 0000000000..b11192b8b1
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/di/AppBindings.kt
@@ -0,0 +1,12 @@
+package io.element.android.x.di
+
+import com.squareup.anvil.annotations.ContributesTo
+import io.element.android.x.di.AppScope
+import io.element.android.x.matrix.Matrix
+import kotlinx.coroutines.CoroutineScope
+
+@ContributesTo(AppScope::class)
+interface AppBindings {
+ fun coroutineScope(): CoroutineScope
+ fun matrix(): Matrix
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/di/AppComponent.kt b/app/src/main/java/io/element/android/x/di/AppComponent.kt
new file mode 100644
index 0000000000..b12230cbee
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/di/AppComponent.kt
@@ -0,0 +1,16 @@
+package io.element.android.x.di
+
+import android.app.Application
+import com.squareup.anvil.annotations.MergeComponent
+import dagger.BindsInstance
+import dagger.Component
+
+@SingleIn(AppScope::class)
+@MergeComponent(AppScope::class)
+interface AppComponent {
+
+ @Component.Factory
+ interface Factory {
+ fun create(@BindsInstance application: Application): AppComponent
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/di/AppModule.kt b/app/src/main/java/io/element/android/x/di/AppModule.kt
new file mode 100644
index 0000000000..681365aa9f
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/di/AppModule.kt
@@ -0,0 +1,20 @@
+package io.element.android.x.di
+
+import com.squareup.anvil.annotations.ContributesTo
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.plus
+
+@Module
+@ContributesTo(AppScope::class)
+object AppModule {
+
+ @Provides
+ @SingleIn(AppScope::class)
+ fun providesAppCoroutineScope(): CoroutineScope {
+ return MainScope() + CoroutineName("ElementX Scope")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/initializer/CoilInitializer.kt b/app/src/main/java/io/element/android/x/initializer/CoilInitializer.kt
new file mode 100644
index 0000000000..8db0737e51
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/initializer/CoilInitializer.kt
@@ -0,0 +1,36 @@
+package io.element.android.x.initializer
+
+import android.content.Context
+import androidx.startup.Initializer
+import coil.Coil
+import coil.ImageLoader
+import coil.ImageLoaderFactory
+import io.element.android.x.core.di.DaggerComponentOwner
+import io.element.android.x.core.di.bindings
+import io.element.android.x.di.AppBindings
+import io.element.android.x.di.AppComponent
+
+class CoilInitializer : Initializer {
+
+ override fun create(context: Context) {
+ Coil.setImageLoader(ElementImageLoaderFactory(context))
+ }
+
+ override fun dependencies(): MutableList>> = mutableListOf()
+}
+
+private class ElementImageLoaderFactory(
+ private val context: Context
+) :
+ ImageLoaderFactory {
+ override fun newImageLoader(): ImageLoader {
+ return ImageLoader
+ .Builder(context)
+ .components {
+ context.bindings().matrix().registerCoilComponents(this)
+ }
+ .build()
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/initializer/MavericksInitializer.kt b/app/src/main/java/io/element/android/x/initializer/MavericksInitializer.kt
new file mode 100644
index 0000000000..fe6fcc07df
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/initializer/MavericksInitializer.kt
@@ -0,0 +1,16 @@
+package io.element.android.x.initializer
+
+import android.content.Context
+import androidx.startup.Initializer
+import com.airbnb.mvrx.Mavericks
+
+class MavericksInitializer : Initializer {
+
+ override fun create(context: Context) {
+ Mavericks.initialize(context)
+ }
+
+ override fun dependencies(): MutableList>> = mutableListOf()
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/element/android/x/initializer/TimberInitializer.kt b/app/src/main/java/io/element/android/x/initializer/TimberInitializer.kt
new file mode 100644
index 0000000000..e8fe1f7118
--- /dev/null
+++ b/app/src/main/java/io/element/android/x/initializer/TimberInitializer.kt
@@ -0,0 +1,14 @@
+package io.element.android.x.initializer
+
+import android.content.Context
+import androidx.startup.Initializer
+import timber.log.Timber
+
+class TimberInitializer: Initializer {
+
+ override fun create(context: Context) {
+ Timber.plant(Timber.DebugTree())
+ }
+
+ override fun dependencies(): MutableList>> = mutableListOf()
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2eed05aef1..704c0236ac 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -14,6 +14,7 @@ recyclerview = "1.2.1"
lifecycle = "2.5.1"
activity_compose = "1.6.1"
fragment = "1.5.5"
+startup = "1.1.1"
# Compose
compose_compiler = "1.3.2"
@@ -48,7 +49,7 @@ compose_destinations = "1.7.23-beta"
jsoup = "1.15.3"
# DI
-dagger = "2.32"
+dagger = "2.43"
anvil = "2.4.2"
[libraries]
@@ -68,6 +69,7 @@ androidx_lifecycle_runtime = { module = "androidx.lifecycle:lifecycle-runtime-kt
androidx_lifecycle_viewmodel_compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
androidx_activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity_compose" }
androidx_fragment = {module = "androidx.fragment:fragment-ktx", version.ref = "fragment"}
+androidx_startup = { module = "androidx.startup:startup-runtime", version.ref = "startup"}
androidx_compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" }
androidx_compose_foundation = { group = "androidx.compose.foundation", name = "foundation" }
@@ -111,9 +113,11 @@ showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
+
# Di
inject = {module = "javax.inject:javax.inject", version = "1"}
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
+dagger_compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
anvil_compiler_api = { module = "com.squareup.anvil:compiler-api", version.ref = "anvil" }
anvil_compiler_utils = { module = "com.squareup.anvil:compiler-utils", version.ref = "anvil" }
diff --git a/libraries/matrix/build.gradle.kts b/libraries/matrix/build.gradle.kts
index b420b32794..5001895635 100644
--- a/libraries/matrix/build.gradle.kts
+++ b/libraries/matrix/build.gradle.kts
@@ -1,5 +1,6 @@
plugins {
id("io.element.android-library")
+ alias(libs.plugins.anvil)
kotlin("plugin.serialization") version "1.7.20"
}
@@ -7,8 +8,13 @@ android {
namespace = "io.element.android.x.sdk.matrix"
}
+anvil {
+ generateDaggerFactories.set(true)
+}
+
dependencies {
api(project(":libraries:rustsdk"))
+ implementation(project(":libraries:daggerscopes"))
implementation(project(":libraries:core"))
implementation(libs.timber)
implementation("net.java.dev.jna:jna:5.12.1@aar")
diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt
index 5be629b7f8..e6a7cdda2c 100644
--- a/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt
+++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt
@@ -1,8 +1,10 @@
package io.element.android.x.matrix
-import android.content.Context
+import android.app.Application
import coil.ComponentRegistry
import io.element.android.x.core.coroutine.CoroutineDispatchers
+import io.element.android.x.di.AppScope
+import io.element.android.x.di.SingleIn
import io.element.android.x.matrix.media.MediaFetcher
import io.element.android.x.matrix.media.MediaKeyer
import io.element.android.x.matrix.session.SessionStore
@@ -19,10 +21,12 @@ import timber.log.Timber
import java.io.File
import java.util.*
import java.util.concurrent.Executors
+import javax.inject.Inject
-class Matrix(
+@SingleIn(AppScope::class)
+class Matrix @Inject constructor(
private val coroutineScope: CoroutineScope,
- context: Context,
+ context: Application,
) {
private val coroutineDispatchers = CoroutineDispatchers(
io = Dispatchers.IO,
@@ -58,7 +62,7 @@ class Matrix(
return matrixClient.value.get()
}
- fun registerComponents(builder: ComponentRegistry.Builder) {
+ fun registerCoilComponents(builder: ComponentRegistry.Builder) {
builder.add(MediaKeyer())
builder.add(MediaFetcher.Factory(this))
}
diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt
index b7173b0b2b..6497791622 100644
--- a/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt
+++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt
@@ -1,7 +1,7 @@
package io.element.android.x.matrix
import android.annotation.SuppressLint
-import android.content.Context
+import android.app.Application
import io.element.android.x.matrix.tracing.TracingConfigurations
import io.element.android.x.matrix.tracing.setupTracing
import io.element.android.x.sdk.matrix.BuildConfig
@@ -12,7 +12,7 @@ object MatrixInstance {
@SuppressLint("StaticFieldLeak")
private lateinit var instance: Matrix
- fun init(context: Context, coroutineScope: CoroutineScope) {
+ fun init(context: Application, coroutineScope: CoroutineScope) {
if (BuildConfig.DEBUG) {
setupTracing(TracingConfigurations.debug)
} else {