├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── colors.xml │ │ │ └── themes.xml │ │ ├── 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 │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── layout │ │ │ └── activity_main.xml │ │ ├── values-night │ │ │ └── themes.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ └── ca │ │ │ └── nick │ │ │ └── multimodulenavigation │ │ │ ├── di │ │ │ ├── AppComponentProvider.kt │ │ │ ├── SubcomponentsModule.kt │ │ │ ├── MainScope.kt │ │ │ ├── FragmentKey.kt │ │ │ ├── AppComponent.kt │ │ │ ├── MainModule.kt │ │ │ ├── MainComponent.kt │ │ │ └── FragmentsModule.kt │ │ │ ├── App.kt │ │ │ ├── OnItemClickedDirections.kt │ │ │ ├── AppFragmentFactory.kt │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── detail ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── ca │ │ │ └── nick │ │ │ └── detail │ │ │ └── DetailFragment.kt │ │ └── res │ │ └── layout │ │ └── detail_fragment.xml ├── proguard-rules.pro └── build.gradle ├── list ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ ├── java │ │ └── ca │ │ │ └── nick │ │ │ └── list │ │ │ ├── OnItemClicked.kt │ │ │ ├── SomeHeavyWeightDependency.kt │ │ │ └── ListFragment.kt │ │ ├── AndroidManifest.xml │ │ └── res │ │ └── layout │ │ └── list_fragment.xml ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── README.md ├── .gitignore ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /detail/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /list/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /list/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /detail/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':detail' 2 | include ':list' 3 | include ':app' 4 | rootProject.name = "multimodulenavigation" -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | multimodulenavigation 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /list/src/main/java/ca/nick/list/OnItemClicked.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.list 2 | 3 | interface OnItemClicked { 4 | fun onItemClicked() 5 | } -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihk/multi-module-navigation/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /list/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/AppComponentProvider.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | interface AppComponentProvider { 4 | val appComponent: AppComponent 5 | } -------------------------------------------------------------------------------- /detail/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /list/src/main/java/ca/nick/list/SomeHeavyWeightDependency.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.list 2 | 3 | import javax.inject.Inject 4 | import javax.inject.Singleton 5 | 6 | @Singleton 7 | class SomeHeavyWeightDependency @Inject constructor() -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/SubcomponentsModule.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import dagger.Module 4 | 5 | @Module(subcomponents = [MainComponent::class]) 6 | object SubcomponentsModule -------------------------------------------------------------------------------- /detail/src/main/java/ca/nick/detail/DetailFragment.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.detail 2 | 3 | import androidx.fragment.app.Fragment 4 | import javax.inject.Inject 5 | 6 | class DetailFragment @Inject constructor() : Fragment(R.layout.detail_fragment) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # multi-module-navigation 2 | A quick and dirty project to show multi-(Gradle)module navigation facilitated by Dagger 3 | 4 | This is a repo to accompany my Medium article: 5 | https://medium.com/@nicholas.rose/multi-module-navigation-with-dagger2-f747db186343 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Dec 27 11:42:21 EST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | .idea/ -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/MainScope.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import javax.inject.Scope 4 | 5 | @Target( 6 | AnnotationTarget.CLASS, 7 | AnnotationTarget.FUNCTION 8 | ) 9 | @Retention(AnnotationRetention.RUNTIME) 10 | @Scope 11 | annotation class MainScope -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import androidx.fragment.app.Fragment 4 | import dagger.MapKey 5 | import kotlin.reflect.KClass 6 | 7 | @Target( 8 | AnnotationTarget.FUNCTION, 9 | AnnotationTarget.PROPERTY_GETTER, 10 | AnnotationTarget.PROPERTY_SETTER 11 | ) 12 | @Retention(AnnotationRetention.RUNTIME) 13 | @MapKey 14 | annotation class FragmentKey(val value: KClass) -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/App.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation 2 | 3 | import android.app.Application 4 | import ca.nick.multimodulenavigation.di.AppComponent 5 | import ca.nick.multimodulenavigation.di.AppComponentProvider 6 | import ca.nick.multimodulenavigation.di.DaggerAppComponent 7 | 8 | @Suppress("unused") 9 | class App : Application(), AppComponentProvider { 10 | 11 | override val appComponent: AppComponent by lazy { 12 | DaggerAppComponent 13 | .factory() 14 | .application(this) 15 | } 16 | } -------------------------------------------------------------------------------- /detail/src/main/res/layout/detail_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/AppComponent.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import android.app.Application 4 | import dagger.BindsInstance 5 | import dagger.Component 6 | import javax.inject.Singleton 7 | 8 | @Singleton 9 | @Component( 10 | modules = [ 11 | SubcomponentsModule::class 12 | ] 13 | ) 14 | interface AppComponent { 15 | 16 | @Component.Factory 17 | interface Factory { 18 | fun application(@BindsInstance application: Application): AppComponent 19 | } 20 | 21 | fun mainComponentFactory(): MainComponent.Factory 22 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/OnItemClickedDirections.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation 2 | 3 | import androidx.fragment.app.FragmentManager 4 | import ca.nick.detail.DetailFragment 5 | import ca.nick.list.OnItemClicked 6 | import javax.inject.Inject 7 | 8 | class OnItemClickedDirections @Inject constructor( 9 | private val fragmentManager: FragmentManager 10 | ) : OnItemClicked { 11 | 12 | override fun onItemClicked() { 13 | fragmentManager.beginTransaction() 14 | .replace(R.id.container, DetailFragment()) 15 | .addToBackStack(null) 16 | .commit() 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/MainModule.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import androidx.fragment.app.FragmentFactory 4 | import ca.nick.list.OnItemClicked 5 | import ca.nick.multimodulenavigation.AppFragmentFactory 6 | import ca.nick.multimodulenavigation.OnItemClickedDirections 7 | import dagger.Binds 8 | import dagger.Module 9 | 10 | @Module 11 | abstract class MainModule { 12 | @Binds 13 | abstract fun onItemClicked(onItemClickedDirections: OnItemClickedDirections): OnItemClicked 14 | 15 | @Binds 16 | abstract fun fragmentFactory(appFragmentFactory: AppFragmentFactory): FragmentFactory 17 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/MainComponent.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import androidx.fragment.app.FragmentFactory 4 | import androidx.fragment.app.FragmentManager 5 | import dagger.BindsInstance 6 | import dagger.Subcomponent 7 | 8 | @MainScope 9 | @Subcomponent( 10 | modules = [ 11 | MainModule::class, 12 | FragmentsModule::class 13 | ] 14 | ) 15 | interface MainComponent { 16 | 17 | val fragmentFactory: FragmentFactory 18 | 19 | @Subcomponent.Factory 20 | interface Factory { 21 | fun create(@BindsInstance fragmentManager: FragmentManager): MainComponent 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/di/FragmentsModule.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation.di 2 | 3 | import androidx.fragment.app.Fragment 4 | import ca.nick.detail.DetailFragment 5 | import ca.nick.list.ListFragment 6 | import dagger.Binds 7 | import dagger.Module 8 | import dagger.multibindings.IntoMap 9 | 10 | @Module 11 | abstract class FragmentsModule { 12 | @Binds 13 | @IntoMap 14 | @FragmentKey(ListFragment::class) 15 | abstract fun listFragment(listFragment: ListFragment): Fragment 16 | 17 | @Binds 18 | @IntoMap 19 | @FragmentKey(DetailFragment::class) 20 | abstract fun detailFragment(detailFragment: DetailFragment): Fragment 21 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/nick/multimodulenavigation/AppFragmentFactory.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.multimodulenavigation 2 | 3 | import androidx.fragment.app.Fragment 4 | import androidx.fragment.app.FragmentFactory 5 | import javax.inject.Inject 6 | import javax.inject.Provider 7 | 8 | class AppFragmentFactory @Inject constructor( 9 | private val fragments: Map, @JvmSuppressWildcards Provider> 10 | ) : FragmentFactory() { 11 | 12 | override fun instantiate(classLoader: ClassLoader, className: String): Fragment { 13 | val fragmentClass: Class = loadFragmentClass(classLoader, className) 14 | return fragments[fragmentClass]?.get() ?: super.instantiate(classLoader, className) 15 | } 16 | } -------------------------------------------------------------------------------- /list/src/main/java/ca/nick/list/ListFragment.kt: -------------------------------------------------------------------------------- 1 | package ca.nick.list 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.Button 6 | import androidx.fragment.app.Fragment 7 | import javax.inject.Inject 8 | 9 | class ListFragment @Inject constructor( 10 | private val onItemClicked: OnItemClicked, 11 | @Suppress("unused") 12 | private val someHeavyWeightDependency: SomeHeavyWeightDependency 13 | ) : Fragment(R.layout.list_fragment) { 14 | 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | view.findViewById