├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── mi
│ │ └── best_practice
│ │ ├── App.kt
│ │ └── koin
│ │ └── AppComponent.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.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
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── CommonDependency.kt
│ ├── base_plugin
│ ├── BaseGradlePlugin.kt
│ └── PluginExtensions.kt
│ └── constants
│ ├── AndroidConfig.kt
│ ├── GradleDependency.kt
│ ├── LibraryDependency.kt
│ ├── ModulesDependency.kt
│ └── TestLibraryDependency.kt
├── config
└── detekt.yml
├── dashboard
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── mi
│ │ └── dashboard
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── mi
│ │ │ └── dashboard
│ │ │ ├── DashboardViewModel.kt
│ │ │ ├── FirstFragment.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── SecondFragment.kt
│ │ │ └── koin
│ │ │ └── FeatureDashboardModule.kt
│ └── res
│ │ ├── layout
│ │ ├── activity_dashboard.xml
│ │ ├── content_main.xml
│ │ ├── fragment_first.xml
│ │ └── fragment_second.xml
│ │ ├── menu
│ │ └── menu_main.xml
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── mi
│ └── dashboard
│ └── ExampleUnitTest.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── navigation
├── .gitignore
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── mi
│ └── navigation
│ ├── ExtraConstant.kt
│ └── Navigation.kt
└── settings.gradle.kts
/.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 |
--------------------------------------------------------------------------------
/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/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/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/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MoIbrahim15/Android-Kotlin-Modularization-MVI/102e64cc3c5b961b649c6c60e1c0b3f2c8e7b4c3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Best Practice
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
2 |
3 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
4 | plugins {
5 | id(GradlePluginId.KTLINT_GRADLE) version CoreVersion.KTLINT_GRADLE
6 | id(GradlePluginId.DETEKT) version CoreVersion.DETEKT
7 | }
8 |
9 | buildscript {
10 | repositories {
11 | // Android plugin & support libraries
12 | google()
13 |
14 | // Main open-source repository
15 | jcenter()
16 |
17 | // Ktlint Gradle
18 | maven(GradlePluginId.KTLINT_MAVEN)
19 | }
20 | dependencies {
21 | classpath(GradleClasspath.ANDROID_GRADLE)
22 | classpath(kotlin(GradleClasspath.KOTLIN_PlUGIN, version = CoreVersion.KOTLIN))
23 | classpath(GradleClasspath.SAFE_ARGS)
24 | classpath(GradleClasspath.KTLINT_CLASSPATH)
25 | }
26 | }
27 |
28 | allprojects {
29 | repositories {
30 | google()
31 | jcenter()
32 | }
33 |
34 | // We want to apply ktlint at all project level because it also checks build gradle files
35 | plugins.apply(GradlePluginId.KTLINT_GRADLE)
36 | // Ktlint configuration for sub-projects
37 | ktlint {
38 | version.set(CoreVersion.KTLINT)
39 | verbose.set(true)
40 | android.set(true)
41 | reporters {
42 | reporter(ReporterType.CHECKSTYLE)
43 | }
44 | ignoreFailures.set(true)
45 | filter {
46 | exclude("**/generated/**")
47 | }
48 | }
49 |
50 | plugins.apply(GradlePluginId.DETEKT)
51 |
52 | detekt {
53 | config = files("${project.rootDir}/config/detekt.yml")
54 | parallel = true
55 | }
56 | }
57 |
58 | tasks.register("clean", Delete::class) {
59 | delete(rootProject.buildDir)
60 | }
61 |
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | //The kotlin-dsl plugin requires a repository to be declared
6 | repositories {
7 | mavenCentral()
8 | google()
9 | jcenter()
10 | }
11 |
12 | gradlePlugin {
13 | plugins {
14 | register("base-gradle-plugin") {
15 | id = "base-gradle-plugin"
16 | implementationClass = "base_plugin.BaseGradlePlugin"
17 | }
18 | }
19 | }
20 |
21 |
22 | dependencies {
23 | /* Depend on the android gradle plugin, since we want to access it in our plugin */
24 | implementation("com.android.tools.build:gradle:3.5.3")
25 | /* Depend on the kotlin plugin, since we want to access it in our plugin */
26 | implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
27 | }
28 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/CommonDependency.kt:
--------------------------------------------------------------------------------
1 | import org.gradle.api.artifacts.Dependency
2 | import org.gradle.api.artifacts.dsl.DependencyHandler
3 |
4 | /*
5 | Define common dependencies, so they can be easily updated across feature modules
6 | */
7 | fun DependencyHandler.addTestDependencies() {
8 | testImplementation(TestLibraryDependency.JUNIT)
9 | testImplementation(TestLibraryDependency.KOIN)
10 | androidTestImplementation(TestLibraryDependency.JUNIT_ANDROID)
11 | androidTestImplementation(TestLibraryDependency.ESPRESSO)
12 | }
13 |
14 | /*
15 | * These extensions mimic the extensions that are generated on the fly by Gradle.
16 | * They are used here to provide above dependency syntax that mimics Gradle Kotlin DSL syntax in module\build.gradle.kts files.
17 | */
18 | fun DependencyHandler.implementation(dependencyNotation: Any): Dependency? =
19 | add("implementation", dependencyNotation)
20 |
21 | private fun DependencyHandler.api(dependencyNotation: Any): Dependency? =
22 | add("api", dependencyNotation)
23 |
24 | private fun DependencyHandler.kapt(dependencyNotation: Any): Dependency? =
25 | add("kapt", dependencyNotation)
26 |
27 | private fun DependencyHandler.testImplementation(dependencyNotation: Any): Dependency? =
28 | add("testImplementation", dependencyNotation)
29 |
30 | private fun DependencyHandler.androidTestImplementation(dependencyNotation: Any): Dependency? =
31 | add("androidTestImplementation", dependencyNotation)
32 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/base_plugin/BaseGradlePlugin.kt:
--------------------------------------------------------------------------------
1 | package base_plugin
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 |
6 | open class BaseGradlePlugin : Plugin {
7 | override fun apply(project: Project) {
8 | project.configureDefaultPlugins()
9 | project.configureAndroidApp()
10 | project.configureDependencies()
11 | }
12 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/base_plugin/PluginExtensions.kt:
--------------------------------------------------------------------------------
1 | package base_plugin
2 | import com.android.build.gradle.BaseExtension
3 | import org.gradle.api.Project
4 | import org.gradle.api.JavaVersion
5 | import org.gradle.kotlin.dsl.getByType
6 | import org.gradle.kotlin.dsl.dependencies
7 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
8 |
9 | internal fun Project.configureDefaultPlugins() {
10 | plugins.apply(GradlePluginId.ANDROID)
11 | plugins.apply(GradlePluginId.ANDROID_EXT)
12 | }
13 |
14 | private typealias AndroidBaseExtension = BaseExtension
15 |
16 | internal fun Project.configureAndroidApp() = this.extensions.getByType().run {
17 | compileSdkVersion(AndroidConfig.COMPILE_SDK_VERSION)
18 | defaultConfig {
19 | minSdkVersion(AndroidConfig.MIN_SDK_VERSION)
20 | targetSdkVersion(AndroidConfig.TARGET_SDK_VERSION)
21 | versionCode = AndroidConfig.VERSION_CODE
22 | versionName = AndroidConfig.VERSION_NAME
23 | testInstrumentationRunner = AndroidConfig.TEST_INSTRUMENTATION_RUNNER
24 | }
25 | buildTypes {
26 | getByName(BuildType.DEBUG) {
27 | isTestCoverageEnabled = true
28 | }
29 | getByName(BuildType.RELEASE) {
30 | isMinifyEnabled = false
31 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
32 | }
33 | }
34 |
35 | compileOptions {
36 | sourceCompatibility = JavaVersion.VERSION_1_8
37 | targetCompatibility = JavaVersion.VERSION_1_8
38 | }
39 |
40 | project.tasks.withType(KotlinCompile::class.java).configureEach {
41 | kotlinOptions {
42 | jvmTarget = "1.8"
43 | }
44 | }
45 | }
46 |
47 | internal fun Project.configureDependencies() = this.dependencies {
48 | add("implementation", LibraryDependency.KOTLIN_STD)
49 | //koin - di
50 | add("implementation", LibraryDependency.KOIN)
51 | add("implementation", LibraryDependency.KOIN_VIEWMODEL)
52 | add("implementation", LibraryDependency.KOIN_SCOPE)
53 | }
54 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/constants/AndroidConfig.kt:
--------------------------------------------------------------------------------
1 | object AndroidConfig {
2 |
3 | const val COMPILE_SDK_VERSION = 29
4 | const val MIN_SDK_VERSION = 21
5 | const val TARGET_SDK_VERSION = 29
6 | const val VERSION_CODE = 1
7 | const val VERSION_NAME = "1"
8 |
9 | const val ID = "com.mi.best_practice"
10 | const val TEST_INSTRUMENTATION_RUNNER = "androidx.test.runner.AndroidJUnitRunner"
11 | }
12 |
13 |
14 | interface BuildType {
15 |
16 | companion object {
17 | const val RELEASE = "release"
18 | const val DEBUG = "release"
19 | }
20 |
21 | val isMinifyEnabled: Boolean
22 | }
23 |
24 | object BuildTypeDebug : BuildType {
25 | override val isMinifyEnabled = false
26 | }
27 |
28 | object BuildTypeRelease : BuildType {
29 | override val isMinifyEnabled = true
30 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/constants/GradleDependency.kt:
--------------------------------------------------------------------------------
1 | object CoreVersion{
2 | const val KOTLIN = "1.3.61"
3 | const val NAVIGATION = "2.2.0"
4 | const val ANDROID_GRADLE = "3.5.3"
5 | const val KTLINT_GRADLE = "9.2.1"
6 | const val KTLINT = "0.34.2"
7 | const val DETEKT = "1.0.0"
8 | }
9 |
10 | object GradlePluginId {
11 | const val ANDROID_APP = "com.android.application"
12 | const val ANDROID_LIB = "com.android.library"
13 | const val ANDROID = "kotlin-android"
14 | const val ANDROID_EXT = "kotlin-android-extensions"
15 | const val SAFE_ARGS = "androidx.navigation.safeargs"
16 | const val BASE_GRADLE_PLUGIN = "base-gradle-plugin"
17 | const val KTLINT_GRADLE = "org.jlleitschuh.gradle.ktlint"
18 | const val KTLINT_MAVEN = "https://plugins.gradle.org/m2/"
19 | const val DETEKT = "io.gitlab.arturbosch.detekt"
20 | }
21 |
22 | object GradleClasspath {
23 | const val KOTLIN_PlUGIN = "gradle-plugin"
24 | const val ANDROID_GRADLE = "com.android.tools.build:gradle:${CoreVersion.ANDROID_GRADLE}"
25 | const val SAFE_ARGS = "androidx.navigation:navigation-safe-args-gradle-plugin:${CoreVersion.NAVIGATION}"
26 | const val KTLINT_CLASSPATH ="org.jlleitschuh.gradle:ktlint-gradle:${CoreVersion.KTLINT_GRADLE}"
27 | }
28 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/constants/LibraryDependency.kt:
--------------------------------------------------------------------------------
1 | object LibraryDependency {
2 | object Version {
3 | const val SUPPORT_LIB = "1.1.0"
4 | const val CONSTRAINT = "1.1.3"
5 | const val KOIN = "2.0.1"
6 | }
7 |
8 | const val KOTLIN_STD = "org.jetbrains.kotlin:kotlin-stdlib:${CoreVersion.KOTLIN}"
9 | const val CORE = "androidx.core:core-ktx:${Version.SUPPORT_LIB}"
10 | const val APPCOMPAT = "androidx.appcompat:appcompat:${Version.SUPPORT_LIB}"
11 | const val MATERIAL = "com.google.android.material:material:${Version.SUPPORT_LIB}"
12 | const val CONSTRAINT = "androidx.constraintlayout:constraintlayout:${Version.CONSTRAINT}"
13 | const val NAVIGATION_FRAGMENT = "androidx.navigation:navigation-fragment-ktx:${CoreVersion.NAVIGATION}"
14 | const val NAVIGATION_UI = "androidx.navigation:navigation-ui-ktx:${CoreVersion.NAVIGATION}"
15 | const val KOIN = "org.koin:koin-android:${Version.KOIN}"
16 | const val KOIN_VIEWMODEL = "org.koin:koin-androidx-viewmodel:${Version.KOIN}"
17 | const val KOIN_SCOPE = "org.koin:koin-androidx-scope:${Version.KOIN}"
18 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/constants/ModulesDependency.kt:
--------------------------------------------------------------------------------
1 | object ModulesDependency {
2 | const val APP = ":app"
3 | const val NAVIGATION = ":navigation"
4 | const val DASHBOARD = ":dashboard"
5 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/constants/TestLibraryDependency.kt:
--------------------------------------------------------------------------------
1 | object TestLibraryDependency{
2 | object Version{
3 | const val JUNIT = "4.13"
4 | const val JUNIT_ANDROID = "1.1.1"
5 | const val ESPRESSO = "3.2.0"
6 | }
7 |
8 | const val JUNIT = "junit:junit:${Version.JUNIT}"
9 | const val JUNIT_ANDROID = "androidx.test.ext:junit:${Version.JUNIT_ANDROID}"
10 | const val ESPRESSO = "androidx.test.espresso:espresso-core:${Version.ESPRESSO}"
11 | const val KOIN ="org.koin:koin-test:${LibraryDependency.Version.KOIN}"
12 | }
--------------------------------------------------------------------------------
/config/detekt.yml:
--------------------------------------------------------------------------------
1 | build:
2 | maxIssues: 0
3 | excludeCorrectable: false
4 | weights:
5 | # complexity: 2
6 | # LongParameterList: 1
7 | # style: 1
8 | # comments: 1
9 |
10 | config:
11 | validation: true
12 | # when writing own rules with new properties, exclude the property path e.g.: "my_rule_set,.*>.*>[my_property]"
13 | excludes: ""
14 |
15 | processors:
16 | active: true
17 | exclude:
18 | - 'DetektProgressListener'
19 | # - 'FunctionCountProcessor'
20 | # - 'PropertyCountProcessor'
21 | # - 'ClassCountProcessor'
22 | # - 'PackageCountProcessor'
23 | # - 'KtFileCountProcessor'
24 |
25 | console-reports:
26 | active: true
27 | exclude:
28 | - 'ProjectStatisticsReport'
29 | - 'ComplexityReport'
30 | - 'NotificationReport'
31 | # - 'FindingsReport'
32 | - 'FileBasedFindingsReport'
33 |
34 | comments:
35 | active: true
36 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
37 | CommentOverPrivateFunction:
38 | active: false
39 | CommentOverPrivateProperty:
40 | active: false
41 | EndOfSentenceFormat:
42 | active: false
43 | endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$)
44 | UndocumentedPublicClass:
45 | active: false
46 | searchInNestedClass: true
47 | searchInInnerClass: true
48 | searchInInnerObject: true
49 | searchInInnerInterface: true
50 | UndocumentedPublicFunction:
51 | active: false
52 | UndocumentedPublicProperty:
53 | active: false
54 |
55 | complexity:
56 | active: true
57 | ComplexCondition:
58 | active: true
59 | threshold: 4
60 | ComplexInterface:
61 | active: false
62 | threshold: 10
63 | includeStaticDeclarations: false
64 | ComplexMethod:
65 | active: true
66 | threshold: 15
67 | ignoreSingleWhenExpression: false
68 | ignoreSimpleWhenEntries: false
69 | ignoreNestingFunctions: false
70 | nestingFunctions: run,let,apply,with,also,use,forEach,isNotNull,ifNull
71 | LabeledExpression:
72 | active: false
73 | ignoredLabels: ""
74 | LargeClass:
75 | active: true
76 | threshold: 600
77 | LongMethod:
78 | active: true
79 | threshold: 60
80 | LongParameterList:
81 | active: true
82 | threshold: 6
83 | ignoreDefaultParameters: false
84 | MethodOverloading:
85 | active: false
86 | threshold: 6
87 | NestedBlockDepth:
88 | active: true
89 | threshold: 4
90 | StringLiteralDuplication:
91 | active: false
92 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
93 | threshold: 3
94 | ignoreAnnotation: true
95 | excludeStringsWithLessThan5Characters: true
96 | ignoreStringsRegex: '$^'
97 | TooManyFunctions:
98 | active: true
99 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
100 | thresholdInFiles: 11
101 | thresholdInClasses: 11
102 | thresholdInInterfaces: 11
103 | thresholdInObjects: 11
104 | thresholdInEnums: 11
105 | ignoreDeprecated: false
106 | ignorePrivate: false
107 | ignoreOverridden: false
108 |
109 | coroutines:
110 | active: true
111 | GlobalCoroutineUsage:
112 | active: false
113 | RedundantSuspendModifier:
114 | active: false
115 |
116 | empty-blocks:
117 | active: true
118 | EmptyCatchBlock:
119 | active: true
120 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
121 | EmptyClassBlock:
122 | active: true
123 | EmptyDefaultConstructor:
124 | active: true
125 | EmptyDoWhileBlock:
126 | active: true
127 | EmptyElseBlock:
128 | active: true
129 | EmptyFinallyBlock:
130 | active: true
131 | EmptyForBlock:
132 | active: true
133 | EmptyFunctionBlock:
134 | active: true
135 | ignoreOverridden: false
136 | EmptyIfBlock:
137 | active: true
138 | EmptyInitBlock:
139 | active: true
140 | EmptyKtFile:
141 | active: true
142 | EmptySecondaryConstructor:
143 | active: true
144 | EmptyWhenBlock:
145 | active: true
146 | EmptyWhileBlock:
147 | active: true
148 |
149 | exceptions:
150 | active: true
151 | ExceptionRaisedInUnexpectedLocation:
152 | active: false
153 | methodNames: 'toString,hashCode,equals,finalize'
154 | InstanceOfCheckForException:
155 | active: false
156 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
157 | NotImplementedDeclaration:
158 | active: false
159 | PrintStackTrace:
160 | active: false
161 | RethrowCaughtException:
162 | active: false
163 | ReturnFromFinally:
164 | active: false
165 | ignoreLabeled: false
166 | SwallowedException:
167 | active: false
168 | ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException'
169 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
170 | ThrowingExceptionFromFinally:
171 | active: false
172 | ThrowingExceptionInMain:
173 | active: false
174 | ThrowingExceptionsWithoutMessageOrCause:
175 | active: false
176 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
177 | ThrowingNewInstanceOfSameException:
178 | active: false
179 | TooGenericExceptionCaught:
180 | active: true
181 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
182 | exceptionNames:
183 | - ArrayIndexOutOfBoundsException
184 | - Error
185 | - Exception
186 | - IllegalMonitorStateException
187 | - NullPointerException
188 | - IndexOutOfBoundsException
189 | - RuntimeException
190 | - Throwable
191 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
192 | TooGenericExceptionThrown:
193 | active: true
194 | exceptionNames:
195 | - Error
196 | - Exception
197 | - Throwable
198 | - RuntimeException
199 |
200 | formatting:
201 | active: true
202 | android: false
203 | autoCorrect: true
204 | AnnotationOnSeparateLine:
205 | active: false
206 | autoCorrect: true
207 | ChainWrapping:
208 | active: true
209 | autoCorrect: true
210 | CommentSpacing:
211 | active: true
212 | autoCorrect: true
213 | EnumEntryNameCase:
214 | active: false
215 | autoCorrect: true
216 | Filename:
217 | active: true
218 | FinalNewline:
219 | active: true
220 | autoCorrect: true
221 | ImportOrdering:
222 | active: false
223 | autoCorrect: true
224 | Indentation:
225 | active: false
226 | autoCorrect: true
227 | indentSize: 4
228 | continuationIndentSize: 4
229 | MaximumLineLength:
230 | active: true
231 | maxLineLength: 120
232 | ModifierOrdering:
233 | active: true
234 | autoCorrect: true
235 | MultiLineIfElse:
236 | active: true
237 | autoCorrect: true
238 | NoBlankLineBeforeRbrace:
239 | active: true
240 | autoCorrect: true
241 | NoConsecutiveBlankLines:
242 | active: true
243 | autoCorrect: true
244 | NoEmptyClassBody:
245 | active: true
246 | autoCorrect: true
247 | NoEmptyFirstLineInMethodBlock:
248 | active: false
249 | autoCorrect: true
250 | NoLineBreakAfterElse:
251 | active: true
252 | autoCorrect: true
253 | NoLineBreakBeforeAssignment:
254 | active: true
255 | autoCorrect: true
256 | NoMultipleSpaces:
257 | active: true
258 | autoCorrect: true
259 | NoSemicolons:
260 | active: true
261 | autoCorrect: true
262 | NoTrailingSpaces:
263 | active: true
264 | autoCorrect: true
265 | NoUnitReturn:
266 | active: true
267 | autoCorrect: true
268 | NoUnusedImports:
269 | active: true
270 | autoCorrect: true
271 | NoWildcardImports:
272 | active: true
273 | PackageName:
274 | active: true
275 | autoCorrect: true
276 | ParameterListWrapping:
277 | active: true
278 | autoCorrect: true
279 | indentSize: 4
280 | SpacingAroundColon:
281 | active: true
282 | autoCorrect: true
283 | SpacingAroundComma:
284 | active: true
285 | autoCorrect: true
286 | SpacingAroundCurly:
287 | active: true
288 | autoCorrect: true
289 | SpacingAroundDot:
290 | active: true
291 | autoCorrect: true
292 | SpacingAroundKeyword:
293 | active: true
294 | autoCorrect: true
295 | SpacingAroundOperators:
296 | active: true
297 | autoCorrect: true
298 | SpacingAroundParens:
299 | active: true
300 | autoCorrect: true
301 | SpacingAroundRangeOperator:
302 | active: true
303 | autoCorrect: true
304 | StringTemplate:
305 | active: true
306 | autoCorrect: true
307 |
308 | naming:
309 | active: true
310 | ClassNaming:
311 | active: true
312 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
313 | classPattern: '[A-Z$][a-zA-Z0-9$]*'
314 | ConstructorParameterNaming:
315 | active: true
316 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
317 | parameterPattern: '[a-z][A-Za-z0-9]*'
318 | privateParameterPattern: '[a-z][A-Za-z0-9]*'
319 | excludeClassPattern: '$^'
320 | ignoreOverridden: true
321 | EnumNaming:
322 | active: true
323 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
324 | enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*'
325 | ForbiddenClassName:
326 | active: false
327 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
328 | forbiddenName: ''
329 | FunctionMaxLength:
330 | active: false
331 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
332 | maximumFunctionNameLength: 30
333 | FunctionMinLength:
334 | active: false
335 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
336 | minimumFunctionNameLength: 3
337 | FunctionNaming:
338 | active: true
339 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
340 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
341 | excludeClassPattern: '$^'
342 | ignoreOverridden: true
343 | FunctionParameterNaming:
344 | active: true
345 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
346 | parameterPattern: '[a-z][A-Za-z0-9]*'
347 | excludeClassPattern: '$^'
348 | ignoreOverridden: true
349 | InvalidPackageDeclaration:
350 | active: false
351 | rootPackage: ''
352 | MatchingDeclarationName:
353 | active: true
354 | MemberNameEqualsClassName:
355 | active: true
356 | ignoreOverridden: true
357 | ObjectPropertyNaming:
358 | active: true
359 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
360 | constantPattern: '[A-Za-z][_A-Za-z0-9]*'
361 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
362 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
363 | PackageNaming:
364 | active: true
365 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
366 | packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$'
367 | TopLevelPropertyNaming:
368 | active: true
369 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
370 | constantPattern: '[A-Z][_A-Z0-9]*'
371 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
372 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
373 | VariableMaxLength:
374 | active: false
375 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
376 | maximumVariableNameLength: 64
377 | VariableMinLength:
378 | active: false
379 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
380 | minimumVariableNameLength: 1
381 | VariableNaming:
382 | active: true
383 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
384 | variablePattern: '[a-z][A-Za-z0-9]*'
385 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
386 | excludeClassPattern: '$^'
387 | ignoreOverridden: true
388 |
389 | performance:
390 | active: true
391 | ArrayPrimitive:
392 | active: true
393 | ForEachOnRange:
394 | active: true
395 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
396 | SpreadOperator:
397 | active: true
398 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
399 | UnnecessaryTemporaryInstantiation:
400 | active: true
401 |
402 | potential-bugs:
403 | active: true
404 | Deprecation:
405 | active: false
406 | DuplicateCaseInWhenExpression:
407 | active: true
408 | EqualsAlwaysReturnsTrueOrFalse:
409 | active: true
410 | EqualsWithHashCodeExist:
411 | active: true
412 | ExplicitGarbageCollectionCall:
413 | active: true
414 | HasPlatformType:
415 | active: false
416 | ImplicitDefaultLocale:
417 | active: false
418 | InvalidRange:
419 | active: true
420 | IteratorHasNextCallsNextMethod:
421 | active: true
422 | IteratorNotThrowingNoSuchElementException:
423 | active: true
424 | LateinitUsage:
425 | active: false
426 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
427 | excludeAnnotatedProperties: ""
428 | ignoreOnClassesPattern: ""
429 | MapGetWithNotNullAssertionOperator:
430 | active: false
431 | MissingWhenCase:
432 | active: true
433 | RedundantElseInWhen:
434 | active: true
435 | UnconditionalJumpStatementInLoop:
436 | active: false
437 | UnreachableCode:
438 | active: true
439 | UnsafeCallOnNullableType:
440 | active: true
441 | UnsafeCast:
442 | active: false
443 | UselessPostfixExpression:
444 | active: false
445 | WrongEqualsTypeParameter:
446 | active: true
447 |
448 | style:
449 | active: true
450 | CollapsibleIfStatements:
451 | active: false
452 | DataClassContainsFunctions:
453 | active: false
454 | conversionFunctionPrefix: 'to'
455 | DataClassShouldBeImmutable:
456 | active: false
457 | EqualsNullCall:
458 | active: true
459 | EqualsOnSignatureLine:
460 | active: false
461 | ExplicitCollectionElementAccessMethod:
462 | active: false
463 | ExplicitItLambdaParameter:
464 | active: false
465 | ExpressionBodySyntax:
466 | active: false
467 | includeLineWrapping: false
468 | ForbiddenComment:
469 | active: true
470 | values: 'TODO:,FIXME:,STOPSHIP:'
471 | allowedPatterns: ""
472 | ForbiddenImport:
473 | active: false
474 | imports: ''
475 | forbiddenPatterns: ""
476 | ForbiddenMethodCall:
477 | active: false
478 | methods: ''
479 | ForbiddenPublicDataClass:
480 | active: false
481 | ignorePackages: '*.internal,*.internal.*'
482 | ForbiddenVoid:
483 | active: false
484 | ignoreOverridden: false
485 | ignoreUsageInGenerics: false
486 | FunctionOnlyReturningConstant:
487 | active: true
488 | ignoreOverridableFunction: true
489 | excludedFunctions: 'describeContents'
490 | excludeAnnotatedFunction: "dagger.Provides"
491 | LibraryCodeMustSpecifyReturnType:
492 | active: true
493 | LoopWithTooManyJumpStatements:
494 | active: true
495 | maxJumpCount: 1
496 | MagicNumber:
497 | active: true
498 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
499 | ignoreNumbers: '-1,0,1,2'
500 | ignoreHashCodeFunction: true
501 | ignorePropertyDeclaration: false
502 | ignoreLocalVariableDeclaration: false
503 | ignoreConstantDeclaration: true
504 | ignoreCompanionObjectPropertyDeclaration: true
505 | ignoreAnnotation: false
506 | ignoreNamedArgument: true
507 | ignoreEnums: false
508 | ignoreRanges: false
509 | MandatoryBracesIfStatements:
510 | active: false
511 | MaxLineLength:
512 | active: true
513 | maxLineLength: 120
514 | excludePackageStatements: true
515 | excludeImportStatements: true
516 | excludeCommentStatements: false
517 | MayBeConst:
518 | active: true
519 | ModifierOrder:
520 | active: true
521 | NestedClassesVisibility:
522 | active: false
523 | NewLineAtEndOfFile:
524 | active: true
525 | NoTabs:
526 | active: false
527 | OptionalAbstractKeyword:
528 | active: true
529 | OptionalUnit:
530 | active: false
531 | OptionalWhenBraces:
532 | active: false
533 | PreferToOverPairSyntax:
534 | active: false
535 | ProtectedMemberInFinalClass:
536 | active: true
537 | RedundantExplicitType:
538 | active: false
539 | RedundantVisibilityModifierRule:
540 | active: false
541 | ReturnCount:
542 | active: true
543 | max: 2
544 | excludedFunctions: "equals"
545 | excludeLabeled: false
546 | excludeReturnFromLambda: true
547 | excludeGuardClauses: false
548 | SafeCast:
549 | active: true
550 | SerialVersionUIDInSerializableClass:
551 | active: false
552 | SpacingBetweenPackageAndImports:
553 | active: false
554 | ThrowsCount:
555 | active: true
556 | max: 2
557 | TrailingWhitespace:
558 | active: false
559 | UnderscoresInNumericLiterals:
560 | active: false
561 | acceptableDecimalLength: 5
562 | UnnecessaryAbstractClass:
563 | active: true
564 | excludeAnnotatedClasses: "dagger.Module"
565 | UnnecessaryAnnotationUseSiteTarget:
566 | active: false
567 | UnnecessaryApply:
568 | active: false
569 | UnnecessaryInheritance:
570 | active: true
571 | UnnecessaryLet:
572 | active: false
573 | UnnecessaryParentheses:
574 | active: false
575 | UntilInsteadOfRangeTo:
576 | active: false
577 | UnusedImports:
578 | active: false
579 | UnusedPrivateClass:
580 | active: true
581 | UnusedPrivateMember:
582 | active: false
583 | allowedNames: "(_|ignored|expected|serialVersionUID)"
584 | UseArrayLiteralsInAnnotations:
585 | active: false
586 | UseCheckOrError:
587 | active: false
588 | UseDataClass:
589 | active: false
590 | excludeAnnotatedClasses: ""
591 | allowVars: false
592 | UseIfInsteadOfWhen:
593 | active: false
594 | UseRequire:
595 | active: false
596 | UselessCallOnNotNull:
597 | active: true
598 | UtilityClassWithPublicConstructor:
599 | active: true
600 | VarCouldBeVal:
601 | active: false
602 | WildcardImport:
603 | active: true
604 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
605 | excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
606 |
--------------------------------------------------------------------------------
/dashboard/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/dashboard/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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