├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.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
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ └── drawable
│ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ └── com
│ │ │ └── mi
│ │ │ └── best_practice
│ │ │ ├── koin
│ │ │ └── AppComponent.kt
│ │ │ └── App.kt
│ │ └── AndroidManifest.xml
├── build.gradle.kts
└── proguard-rules.pro
├── dashboard
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ ├── layout
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── fragment_second.xml
│ │ │ │ ├── fragment_first.xml
│ │ │ │ └── activity_dashboard.xml
│ │ │ └── navigation
│ │ │ │ └── nav_graph.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── mi
│ │ │ │ └── dashboard
│ │ │ │ ├── DashboardViewModel.kt
│ │ │ │ ├── koin
│ │ │ │ └── FeatureDashboardModule.kt
│ │ │ │ ├── FirstFragment.kt
│ │ │ │ ├── SecondFragment.kt
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── mi
│ │ │ └── dashboard
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── mi
│ │ └── dashboard
│ │ └── ExampleInstrumentedTest.kt
├── build.gradle.kts
└── proguard-rules.pro
├── navigation
├── .gitignore
├── consumer-rules.pro
├── build.gradle.kts
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── mi
│ │ │ └── navigation
│ │ │ ├── ExtraConstant.kt
│ │ │ └── Navigation.kt
│ │ └── AndroidManifest.xml
└── proguard-rules.pro
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle.kts
├── .gitignore
├── README.md
├── local.properties
├── gradle.properties
├── gradlew.bat
├── gradlew
└── config
└── detekt.yml
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/dashboard/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/navigation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/navigation/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dashboard/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Best Practice
3 |
4 |
--------------------------------------------------------------------------------
/navigation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(GradlePluginId.ANDROID_LIB)
3 | id(GradlePluginId.BASE_GRADLE_PLUGIN)
4 | }
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/navigation/src/main/java/com/mi/navigation/ExtraConstant.kt:
--------------------------------------------------------------------------------
1 | package com.mi.navigation
2 |
3 | const val EXTRA_USER = "com.mi.navigation.dashboard.extra.user"
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/navigation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/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/MoIbrahim15/Android-Kotlin-Modularization-MVI/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/MoIbrahim15/Android-Kotlin-Modularization-MVI/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/MoIbrahim15/Android-Kotlin-Modularization-MVI/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/MoIbrahim15/Android-Kotlin-Modularization-MVI/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/dashboard/src/main/java/com/mi/dashboard/DashboardViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.mi.dashboard
2 |
3 | import androidx.lifecycle.ViewModel
4 |
5 | class DashboardViewModel : ViewModel()
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mi/best_practice/koin/AppComponent.kt:
--------------------------------------------------------------------------------
1 | package com.mi.best_practice.koin
2 |
3 | import com.mi.dashboard.koin.featureDashboardModule
4 |
5 | val appModules = listOf(featureDashboardModule)
6 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.buildFileName = "build.gradle.kts"
2 |
3 | // this gradle version has an issue with settings kts file to read from constants
4 | include(
5 | ":app",
6 | ":navigation",
7 | ":dashboard"
8 | )
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/dashboard/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(GradlePluginId.ANDROID_APP)
3 | id(GradlePluginId.BASE_GRADLE_PLUGIN)
4 | }
5 |
6 | dependencies {
7 | implementation(project(ModulesDependency.NAVIGATION))
8 | implementation(project(ModulesDependency.DASHBOARD))
9 | }
10 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 12 11:08:11 EET 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-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/dashboard/src/main/java/com/mi/dashboard/koin/FeatureDashboardModule.kt:
--------------------------------------------------------------------------------
1 | package com.mi.dashboard.koin
2 |
3 | import com.mi.dashboard.DashboardViewModel
4 | import org.koin.androidx.viewmodel.dsl.viewModel
5 | import org.koin.dsl.module
6 |
7 | val featureDashboardModule = module {
8 | viewModel { DashboardViewModel() }
9 | }
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android kotlin best practice include :
2 | Modularization
3 | Gradle Depedency managment
4 | Gradle rewritten in Kotlin DSL
5 | Custom Plugin(dependencies with no duplication)
6 | Static Code Analytics (KTLint-Detekt)
7 | KOIN service locator instead of Dagger (dependency injection)
8 | and more...
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/dashboard/src/test/java/com/mi/dashboard/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.mi.dashboard
2 |
3 | import org.junit.Assert.*
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file is automatically generated by Android Studio.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file should *NOT* be checked into Version Control Systems,
5 | # as it contains information specific to your local configuration.
6 | #
7 | # Location of the SDK. This is only used by Gradle.
8 | # For customization when using a Version Control System, please read the
9 | # header note.
10 | sdk.dir=/Users/mohamedibrahim/Library/Android/sdk
--------------------------------------------------------------------------------
/dashboard/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/navigation/src/main/java/com/mi/navigation/Navigation.kt:
--------------------------------------------------------------------------------
1 | package com.mi.navigation
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 |
6 | object Navigation {
7 | fun openDashboard(context: Context, userId: String) =
8 | internalIntent(context, "com.mi.navigation.dashboard.open")
9 | .putExtra(EXTRA_USER, userId)
10 | }
11 |
12 | private fun internalIntent(context: Context, action: String) =
13 | Intent(action).setPackage(context.packageName)
14 |
--------------------------------------------------------------------------------
/dashboard/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(GradlePluginId.ANDROID_LIB)
3 | id(GradlePluginId.BASE_GRADLE_PLUGIN)
4 | id(GradlePluginId.SAFE_ARGS)
5 | }
6 |
7 | dependencies {
8 |
9 | // support
10 | implementation(LibraryDependency.APPCOMPAT)
11 | implementation(LibraryDependency.CORE)
12 | implementation(LibraryDependency.MATERIAL)
13 | implementation(LibraryDependency.CONSTRAINT)
14 | implementation(LibraryDependency.NAVIGATION_FRAGMENT)
15 | implementation(LibraryDependency.NAVIGATION_UI)
16 |
17 | addTestDependencies()
18 | }
19 |
--------------------------------------------------------------------------------
/dashboard/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | dashboard
3 |
4 | Settings
5 |
6 | First Fragment
7 | Second Fragment
8 | Next
9 | Previous
10 |
11 | Hello first fragment
12 | Hello second fragment. Arg: %1$s
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mi/best_practice/App.kt:
--------------------------------------------------------------------------------
1 | package com.mi.best_practice
2 |
3 | import android.app.Application
4 | import com.mi.best_practice.koin.appModules
5 | import org.koin.android.ext.koin.androidContext
6 | import org.koin.android.ext.koin.androidLogger
7 | import org.koin.core.context.startKoin
8 |
9 | class App : Application() {
10 |
11 | override fun onCreate() {
12 | super.onCreate()
13 | configureDi()
14 | }
15 |
16 | private fun configureDi() {
17 | startKoin {
18 | androidLogger()
19 | androidContext(this@App)
20 | modules(appModules)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/dashboard/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/dashboard/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/dashboard/src/androidTest/java/com/mi/dashboard/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.mi.dashboard
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.mi.dashboard", appContext.packageName)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/dashboard/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/navigation/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/dashboard/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/dashboard/src/main/java/com/mi/dashboard/FirstFragment.kt:
--------------------------------------------------------------------------------
1 | package com.mi.dashboard
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.Button
8 | import androidx.fragment.app.Fragment
9 | import androidx.navigation.fragment.findNavController
10 |
11 | /**
12 | * A simple [Fragment] subclass as the default destination in the navigation.
13 | */
14 | class FirstFragment : Fragment() {
15 |
16 | override fun onCreateView(
17 | inflater: LayoutInflater,
18 | container: ViewGroup?,
19 | savedInstanceState: Bundle?
20 | ): View? {
21 | // Inflate the layout for this fragment
22 | return inflater.inflate(R.layout.fragment_first, container, false)
23 | }
24 |
25 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
26 | super.onViewCreated(view, savedInstanceState)
27 |
28 | view.findViewById