├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── compiler.xml ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hadilq │ │ └── guidomia │ │ ├── CustomApplication.kt │ │ └── di │ │ ├── AppComponent.kt │ │ ├── AppModule.kt │ │ ├── fragment │ │ └── FragmentFactoryImpl.kt │ │ └── viewmodel │ │ └── ViewModelFactoryImpl.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 ├── build.gradle.kts ├── buildSrc ├── .gitignore ├── build.gradle.kts └── src │ └── main │ └── kotlin │ ├── ConfigAndroidLibrary.kt │ ├── Depends.kt │ ├── Modules.kt │ ├── Versions.kt │ └── featureflags │ ├── FeatureFlags.kt │ └── Scenario.kt ├── core ├── impl │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── hadilq │ │ │ └── guidomia │ │ │ └── core │ │ │ └── impl │ │ │ └── DispatcherProviderImpl.kt │ │ └── res │ │ └── values │ │ └── strings.xml └── public │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hadilq │ │ └── guidomia │ │ └── core │ │ └── api │ │ ├── DispatcherProvider.kt │ │ ├── FragmentFactory.kt │ │ ├── FragmentKey.kt │ │ ├── SimpleFragmentFactory.kt │ │ ├── SimpleViewModelFactory.kt │ │ ├── ViewBinding.kt │ │ ├── ViewModelFactory.kt │ │ └── ViewModelKey.kt │ └── res │ ├── values-night │ └── themes.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── themes.xml ├── database ├── impl │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── hadilq │ │ └── guidomia │ │ └── database │ │ └── impl │ │ ├── AppDatabase.kt │ │ ├── CarDao.kt │ │ ├── CarDataEntityCommandHook.kt │ │ ├── CarDataEntityCommandImpl.kt │ │ ├── CarEntityMapper.kt │ │ ├── di │ │ └── DatabaseModule.kt │ │ └── entiry │ │ ├── CarEntity.kt │ │ ├── CarWithProsCons.kt │ │ └── ProConEntity.kt └── public │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── hadilq │ └── guidomia │ └── database │ └── api │ ├── CarDataEntity.kt │ ├── CarDataEntityCommand.kt │ └── GetCarEntityCommand.kt ├── di └── public │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── hadilq │ └── guidomia │ └── di │ └── api │ ├── AppScope.kt │ ├── FragmentScope.kt │ ├── RetainScope.kt │ ├── SingleActivityScope.kt │ └── SingleIn.kt ├── doc-image └── dip-module-dependencies-switch.png ├── feature-flags ├── impl │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── hadilq │ │ └── guidomia │ │ └── featureflags │ │ └── impl │ │ └── CommandKuModule.kt └── public │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── hadilq │ └── guidomia │ └── featureflags │ └── api │ └── CommandExecutor.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── guidomia ├── impl │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ └── car_list.json │ │ ├── java │ │ │ └── com │ │ │ │ └── hadilq │ │ │ │ └── guidomia │ │ │ │ └── guidomia │ │ │ │ └── impl │ │ │ │ ├── GuidomiaCommandHook.kt │ │ │ │ ├── data │ │ │ │ ├── datasource │ │ │ │ │ ├── CarDatabaseDataSource.kt │ │ │ │ │ ├── CarsCacheDataSource.kt │ │ │ │ │ └── CarsDataSource.kt │ │ │ │ ├── entity │ │ │ │ │ └── CarDataEntity.kt │ │ │ │ ├── mapper │ │ │ │ │ ├── CarDataMapper.kt │ │ │ │ │ └── CarDatabaseMapper.kt │ │ │ │ └── repository │ │ │ │ │ └── CarsRepository.kt │ │ │ │ ├── domain │ │ │ │ ├── entity │ │ │ │ │ ├── CarEntity.kt │ │ │ │ │ ├── FilterEntity.kt │ │ │ │ │ ├── ImageEntity.kt │ │ │ │ │ ├── MakeEntity.kt │ │ │ │ │ ├── ModelEntity.kt │ │ │ │ │ ├── PriceEntity.kt │ │ │ │ │ └── RateEntity.kt │ │ │ │ └── usecase │ │ │ │ │ ├── GetCars.kt │ │ │ │ │ └── GetFilteredCars.kt │ │ │ │ └── presentation │ │ │ │ ├── CarItemFilter.kt │ │ │ │ ├── CarItemOnClick.kt │ │ │ │ ├── CarModel.kt │ │ │ │ ├── CarModelMapper.kt │ │ │ │ ├── GuidomiaFragment.kt │ │ │ │ ├── GuidomiaNavigatorImpl.kt │ │ │ │ ├── GuidomiaRecyclerAdapter.kt │ │ │ │ ├── GuidomiaViewModel.kt │ │ │ │ └── di │ │ │ │ ├── GuidomiaFragmentComponent.kt │ │ │ │ └── GuidomiaModule.kt │ │ └── res │ │ │ ├── drawable │ │ │ ├── alpine_roadster.jpg │ │ │ ├── bmw_330i.jpg │ │ │ ├── filter_background.xml │ │ │ ├── filter_edittext_background.xml │ │ │ ├── ic_baseline_dehaze_24.xml │ │ │ ├── logo.png │ │ │ ├── mercedez_benz_glc.jpg │ │ │ ├── pros_cons_dot.xml │ │ │ ├── range_rover.jpg │ │ │ ├── star.png │ │ │ └── tacoma.jpg │ │ │ ├── layout │ │ │ ├── car_item.xml │ │ │ ├── filter_item.xml │ │ │ ├── fragment_guidomia.xml │ │ │ ├── line_item.xml │ │ │ └── pros_cons_item.xml │ │ │ └── values │ │ │ ├── dimens.xml │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── hadilq │ │ └── guidomia │ │ └── guidomia │ │ └── impl │ │ ├── data │ │ └── repository │ │ │ └── CarRepositoryTest.kt │ │ └── domain │ │ ├── entity │ │ ├── CarEntityProvider.kt │ │ ├── MakeEntityProvider.kt │ │ └── ModelEntityProvider.kt │ │ └── usecase │ │ └── GetFilteredCarsTest.kt └── public │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── hadilq │ └── guidomia │ └── guidomia │ └── api │ ├── GetGuidomiaNavigatorFactoryCommand.kt │ ├── GuidomiaNavigator.kt │ └── GuidomiaNavigatorFactory.kt ├── settings.gradle.kts └── single-activity ├── impl ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hadilq │ │ └── guidomia │ │ └── singleactivity │ │ └── impl │ │ ├── NavigatorImpl.kt │ │ ├── SingleActivity.kt │ │ └── di │ │ ├── SingleActivityComponent.kt │ │ └── SingleActivityComponentProvider.kt │ └── res │ └── layout │ └── activity_main.xml └── public ├── .gitignore ├── build.gradle.kts └── src └── main ├── AndroidManifest.xml └── java └── com └── hadilq └── guidomia └── singleactivity └── api ├── Navigator.kt └── NavigatorFactory.kt /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .cxx 9 | local.properties 10 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | caches 5 | libraries 6 | modules.xml 7 | workspace.xml 8 | navEditor.xml 9 | assetWizardSettings.xml 10 | jarRepositories.xml 11 | gradle.xml 12 | misc.xml 13 | runConfigurations.xml 14 | vcs.xml 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 121 | 122 | 129 | 130 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean Architecture 2 | 3 | This is a sample app to show best practices up to author's knowledge by trying to 4 | stay close to standard technologies for a highly scalable, maintainable, and testable 5 | Android app. 6 | 7 | ## Technologies 8 | 9 | - Clean Architecture 10 | - Public/Impl modules to handle Dependency Inversion Principle on module level 11 | - Anvil to handle Inversion of Control 12 | - Compile time feature flags 13 | - Dagger to handle Dependency Injection 14 | - Single Activity for faster initialization of pages 15 | - AndroidX 16 | - MVVM 17 | - Kotlin Coroutines 18 | - KotlinX Serialization 19 | - Room database 20 | - JUnit 5 21 | - Mockk 22 | 23 | ### Dependency Inversion Principle 24 | 25 | All modules are depending on each other only by `:public` interfaces, except the `:app` 26 | where is the only user of `:impl` modules. Also by keeping the `:app` as light as possible, 27 | rebuilding time of any `:impl` module will be short. 28 | 29 | ### Dagger 30 | 31 | Defined scopes in Dagger 32 | - AppScope 33 | - SingleActivityScope 34 | - FragmentScope 35 | - RetainScope 36 | 37 | ### Modules 38 | Here we have one root module, which is the `:app`, and one feature module `:guidomia` that 39 | is following clean architecture practices. 40 | Other modules considered as library modules. 41 | 42 | - core 43 | - database 44 | - single-activity 45 | - di 46 | - feature-flags 47 | 48 | For your convenient you may want to put them in separated directories, such as `features`, `libraries`, etc. 49 | 50 | ### Feature Flags 51 | The idea is to switch on/off modules in compile time. We call this concept compile time feature 52 | flags, because they use the same logic of runtime feature flags, the concept that we had before. 53 | Here we have switches for `:database` and `:guidomia` modules, one library module and one feature 54 | module. In this project, where you can find part of its dependency tree here 55 | 56 | ![dependency tree](https://raw.githubusercontent.com/hadilq/CleanArchitecture/main/doc-image/dip-module-dependencies-switch.png) 57 | 58 | the feature flag logic to handle switch off of `:database:impl` is in the `:guidomia:impl`, and 59 | feature flag logic to handle switch off of `:guimomia:impl` is in `:single-activity:impl`. 60 | To switch them on and off, we developed this sample to use "scenario" concept. You can put 61 | `scenario` variable like 62 | 63 | ```properties 64 | scenario=>guidomia>database 65 | ``` 66 | 67 | in `local.properties` file. It will enable `guidomia` and `database` modules, and it's the default 68 | `scenario`, when the developer didn't provide any `scenario` variable in the `local.properties`. 69 | For this project there are two different `scenario`s that developer can use to decrease the 70 | overall build time of the project. They are as following. 71 | 72 | ```properties 73 | scenario=>guidomia 74 | ``` 75 | 76 | or 77 | 78 | ```properties 79 | scenario=> 80 | ``` 81 | 82 | The last one is the root scenario that switch off all plugable modules in this project. Plugable 83 | modules are the one that has a switch. 84 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import featureflags.installScenario 17 | import featureflags.loadScenarioFromLocal 18 | import featureflags.scenarios 19 | 20 | 21 | plugins { 22 | id("com.android.application") 23 | kotlin("android") 24 | kotlin("kapt") 25 | id("com.squareup.anvil") version Versions.anvil 26 | } 27 | 28 | android { 29 | compileSdkVersion(Versions.compileSdk) 30 | defaultConfig { 31 | applicationId = "com.hadilq.guidomia" 32 | minSdkVersion(Versions.minSdk) 33 | targetSdkVersion(Versions.targetSdk) 34 | versionCode = 1 35 | versionName = "1.0" 36 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 37 | } 38 | 39 | buildTypes { 40 | getByName("debug") { 41 | matchingFallbacks.add("release") 42 | } 43 | getByName("release") { 44 | isMinifyEnabled = false 45 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") 46 | } 47 | } 48 | 49 | compileOptions { 50 | sourceCompatibility(JavaVersion.VERSION_1_8) 51 | targetCompatibility(JavaVersion.VERSION_1_8) 52 | } 53 | 54 | kotlinOptions { 55 | jvmTarget = JavaVersion.VERSION_1_8.toString() 56 | freeCompilerArgs = listOf("-Xinline-classes") 57 | } 58 | 59 | packagingOptions { 60 | exclude("META-INF/*.kotlin_module") 61 | } 62 | } 63 | 64 | dependencies { 65 | installScenario(scenarios, project.loadScenarioFromLocal()) 66 | 67 | implementation(project(Modules.corePublic)) 68 | implementation(project(Modules.coreImpl)) 69 | implementation(project(Modules.diPublic)) 70 | implementation(project(Modules.singleActivityPublic)) 71 | implementation(project(Modules.singleActivityImpl)) 72 | implementation(project(Modules.guidomiaPublic)) 73 | implementation(project(Modules.databasePublic)) 74 | implementation(project(Modules.featureFlagsPublic)) 75 | implementation(project(Modules.featureFlagsImpl)) 76 | 77 | kapt(Depends.daggerCompiler) 78 | 79 | implementation(Depends.kotlinStdLib) 80 | implementation(Depends.appCompat) 81 | implementation(Depends.dagger) 82 | implementation(Depends.recyclerView) 83 | } 84 | -------------------------------------------------------------------------------- /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. 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 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/hadilq/guidomia/CustomApplication.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia 17 | 18 | import android.app.Application 19 | import com.github.hadilq.commandku.api.CommandHook 20 | import com.github.hadilq.commandku.api.CommandRegister 21 | import com.hadilq.guidomia.di.AppComponent 22 | import com.hadilq.guidomia.di.DaggerAppComponent 23 | import com.hadilq.guidomia.di.api.AppScope 24 | import com.hadilq.guidomia.di.api.SingleIn 25 | import com.hadilq.guidomia.singleactivity.impl.di.SingleActivityComponent 26 | import com.hadilq.guidomia.singleactivity.impl.di.SingleActivityComponentProvider 27 | import javax.inject.Inject 28 | 29 | @SingleIn(AppScope::class) 30 | class CustomApplication : Application(), SingleActivityComponentProvider { 31 | 32 | private val component: AppComponent by lazy { 33 | DaggerAppComponent.builder() 34 | .application(this) 35 | .build() 36 | } 37 | 38 | override val singleActivityComponentProvider: SingleActivityComponent.Builder 39 | get() = component.singleActivityComponentBuilder() 40 | 41 | @Inject 42 | protected lateinit var commandHookSet: Set<@JvmSuppressWildcards CommandHook> 43 | 44 | @Inject 45 | protected lateinit var commandRegister: CommandRegister 46 | 47 | override fun onCreate() { 48 | super.onCreate() 49 | component.inject(this) 50 | hookUpFeatureFlags() 51 | } 52 | 53 | private fun hookUpFeatureFlags() { 54 | commandHookSet.forEach { it.hookUp(commandRegister) } 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hadilq/guidomia/di/AppComponent.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.di 17 | 18 | import com.hadilq.guidomia.CustomApplication 19 | import com.hadilq.guidomia.di.api.AppScope 20 | import com.hadilq.guidomia.di.api.SingleIn 21 | import com.hadilq.guidomia.singleactivity.impl.di.SingleActivityComponent 22 | import com.squareup.anvil.annotations.MergeComponent 23 | import dagger.BindsInstance 24 | import dagger.Component 25 | 26 | @SingleIn(AppScope::class) 27 | @MergeComponent( 28 | scope = AppScope::class, 29 | modules = [ 30 | AppModule::class 31 | ] 32 | ) 33 | interface AppComponent { 34 | 35 | @Component.Builder 36 | interface Builder { 37 | @BindsInstance 38 | fun application(customApplication: CustomApplication): Builder 39 | fun build(): AppComponent 40 | } 41 | 42 | fun inject(app: CustomApplication) 43 | 44 | fun singleActivityComponentBuilder(): SingleActivityComponent.Builder 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/hadilq/guidomia/di/AppModule.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.di 17 | 18 | import android.content.Context 19 | import com.github.hadilq.commandku.api.CommandHook 20 | import com.github.hadilq.commandku.api.CommandRegister 21 | import com.hadilq.guidomia.CustomApplication 22 | import com.hadilq.guidomia.di.api.AppScope 23 | import com.squareup.anvil.annotations.ContributesMultibinding 24 | import dagger.Binds 25 | import dagger.Module 26 | import javax.inject.Inject 27 | 28 | @Module 29 | interface AppModule { 30 | 31 | @Binds 32 | fun provideContext(app: CustomApplication): Context 33 | } 34 | 35 | @ContributesMultibinding(AppScope::class) 36 | class EmptyHook @Inject constructor() : CommandHook { 37 | override fun hookUp(commandRegister: CommandRegister) { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/hadilq/guidomia/di/fragment/FragmentFactoryImpl.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.di.fragment 17 | 18 | import androidx.fragment.app.Fragment 19 | import com.hadilq.guidomia.core.api.FragmentFactory 20 | import com.hadilq.guidomia.core.api.SimpleFragmentFactory 21 | import com.hadilq.guidomia.di.api.AppScope 22 | import com.squareup.anvil.annotations.ContributesBinding 23 | import javax.inject.Inject 24 | import kotlin.reflect.KClass 25 | 26 | @ContributesBinding(AppScope::class) 27 | class FragmentFactoryImpl @Inject constructor( 28 | private val creators: Map, @JvmSuppressWildcards SimpleFragmentFactory> 29 | ) : FragmentFactory { 30 | 31 | override fun instantiate(clazz: KClass): Fragment = 32 | creators[clazz.java]!!.instantiate() 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/hadilq/guidomia/di/viewmodel/ViewModelFactoryImpl.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.di.viewmodel 17 | 18 | import androidx.lifecycle.ViewModel 19 | import com.hadilq.guidomia.core.api.SimpleViewModelFactory 20 | import com.hadilq.guidomia.core.api.ViewModelFactory 21 | import com.hadilq.guidomia.di.api.AppScope 22 | import com.squareup.anvil.annotations.ContributesBinding 23 | import javax.inject.Inject 24 | 25 | @ContributesBinding(AppScope::class) 26 | class ViewModelFactoryImpl @Inject constructor( 27 | private val creators: Map, @JvmSuppressWildcards SimpleViewModelFactory> 28 | ) : ViewModelFactory { 29 | 30 | @Suppress("UNCHECKED_CAST") 31 | override fun create(modelClass: Class): T = 32 | creators[modelClass]!!.create() as T 33 | } 34 | -------------------------------------------------------------------------------- /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/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hadilq/CleanArchitecture/f4c5b566d22547cc159e193568f87c8210310604/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | buildscript { 17 | repositories { 18 | google() 19 | mavenCentral() 20 | } 21 | dependencies { 22 | classpath("com.android.tools.build:gradle:4.1.3") // Change the version in buildSrc dependencies too. 23 | classpath(kotlin("gradle-plugin", version = Versions.kotlin)) 24 | classpath("de.mannodermaus.gradle.plugins:android-junit5:1.7.1.1") 25 | } 26 | } 27 | 28 | allprojects { 29 | repositories { 30 | google() 31 | mavenCentral() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /buildSrc/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | `kotlin-dsl` 18 | } 19 | 20 | repositories { 21 | google() 22 | mavenCentral() 23 | } 24 | 25 | dependencies { 26 | implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32") 27 | implementation("com.android.tools.build:gradle:4.1.3") 28 | } 29 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/ConfigAndroidLibrary.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import com.android.build.gradle.LibraryExtension 17 | import com.android.builder.core.BuilderConstants 18 | import org.gradle.api.Action 19 | import org.gradle.api.JavaVersion 20 | import org.gradle.api.Project 21 | import org.gradle.api.plugins.ExtensionAware 22 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions 23 | 24 | fun Project.configureAndroidLibrary() { 25 | androidLibrary { 26 | compileSdkVersion(Versions.compileSdk) 27 | 28 | defaultConfig { 29 | minSdkVersion(Versions.minSdk) 30 | targetSdkVersion(Versions.targetSdk) 31 | } 32 | 33 | buildTypes { 34 | getByName("release") { 35 | isMinifyEnabled = false 36 | } 37 | } 38 | 39 | compileOptions { 40 | sourceCompatibility(JavaVersion.VERSION_1_8) 41 | targetCompatibility(JavaVersion.VERSION_1_8) 42 | } 43 | 44 | kotlinOptions { 45 | jvmTarget = JavaVersion.VERSION_1_8.toString() 46 | freeCompilerArgs = listOf("-Xinline-classes") 47 | } 48 | 49 | variantFilter { 50 | if (buildType.name == BuilderConstants.DEBUG) { 51 | ignore = true 52 | } 53 | } 54 | 55 | buildFeatures { 56 | aidl = false 57 | dataBinding = false 58 | viewBinding = false 59 | shaders = false 60 | buildConfig = false 61 | renderScript = false 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * Configures the [android][LibraryExtension] extension. 68 | */ 69 | fun Project.androidLibrary(configure: Action): Unit = 70 | (this as ExtensionAware).extensions.configure("android", configure) 71 | 72 | /** 73 | * Configures the [kotlinOptions][KotlinJvmOptions] extension. 74 | */ 75 | fun LibraryExtension.kotlinOptions(configure: Action): Unit = 76 | (this as ExtensionAware).extensions.configure("kotlinOptions", configure) 77 | 78 | 79 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Depends.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | object Depends { 17 | const val kotlinStdLib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}" 18 | const val kotlinTest = "org.jetbrains.kotlin:kotlin-test:${Versions.kotlin}" 19 | const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}" 20 | const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompat}" 21 | const val material = "com.google.android.material:material:${Versions.material}" 22 | const val constraintLayout = 23 | "androidx.constraintlayout:constraintlayout:${Versions.constraintLayout}" 24 | const val lifecycleCompiler = "androidx.lifecycle:lifecycle-compiler:${Versions.lifecycle}" 25 | const val fragment = "androidx.fragment:fragment-ktx:${Versions.fragment}" 26 | const val viewModel = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.lifecycle}" 27 | const val recyclerView = "androidx.recyclerview:recyclerview:${Versions.recyclerView}" 28 | const val daggerCompiler = "com.google.dagger:dagger-compiler:${Versions.dagger}" 29 | const val dagger = "com.google.dagger:dagger:${Versions.dagger}" 30 | const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}" 31 | const val jsonSerialization = 32 | "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.jsonSerialization}" 33 | const val roomRuntime = "androidx.room:room-runtime:${Versions.room}" 34 | const val roomCompiler = "androidx.room:room-compiler:${Versions.room}" 35 | const val roomKtx = "androidx.room:room-ktx:${Versions.room}" 36 | const val commandKuApi = "com.github.hadilq:command-ku-api:${Versions.commandKu}" 37 | const val commandKuImpl = "com.github.hadilq:command-ku-impl:${Versions.commandKu}" 38 | 39 | const val junit = "junit:junit:${Versions.junit}" 40 | const val junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:${Versions.junitJupiter}" 41 | const val junitJupiterEngine = "org.junit.jupiter:junit-jupiter-engine:${Versions.junitJupiter}" 42 | const val mockk = "io.mockk:mockk:${Versions.mockk}" 43 | const val testExtJunit = "androidx.test.ext:junit:${Versions.testExtJunit}" 44 | const val espressoCore = "androidx.test.espresso:espresso-core:${Versions.espressoCore}" 45 | } 46 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Modules.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | object Modules { 17 | const val corePublic = ":core:public" 18 | const val coreImpl = ":core:impl" 19 | const val diPublic = ":di:public" 20 | const val singleActivityPublic = ":single-activity:public" 21 | const val singleActivityImpl = ":single-activity:impl" 22 | const val guidomiaPublic = ":guidomia:public" 23 | const val guidomiaImpl = ":guidomia:impl" 24 | const val databaseImpl = ":database:impl" 25 | const val databasePublic = ":database:public" 26 | const val featureFlagsImpl = ":feature-flags:impl" 27 | const val featureFlagsPublic = ":feature-flags:public" 28 | } 29 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Versions.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | object Versions { 17 | const val compileSdk = 30 18 | const val targetSdk = 30 19 | const val minSdk = 16 20 | 21 | const val kotlin = "1.4.32" // Change the version in buildSrc dependencies too. 22 | 23 | const val coreKtx = "1.3.2" 24 | const val appCompat = "1.2.0" 25 | const val material = "1.3.0" 26 | const val constraintLayout = "2.0.4" 27 | const val lifecycle = "2.3.1" 28 | const val recyclerView = "1.1.0" 29 | const val fragment = "1.3.2" 30 | const val dagger = "2.34.1" 31 | const val anvil = "2.2.1" 32 | const val coroutines = "1.4.3" 33 | const val serialization = "1.4.30" 34 | const val jsonSerialization = "1.1.0" 35 | const val room = "2.2.6" 36 | const val commandKu = "0.1.0" 37 | 38 | const val junit = "4.13.2" 39 | const val junitJupiter = "5.7.1" 40 | const val mockk = "1.11.0" 41 | const val testExtJunit = "1.1.2" 42 | const val espressoCore = "3.3.0" 43 | } 44 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/featureflags/FeatureFlags.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package featureflags 17 | 18 | import org.gradle.api.Project 19 | import org.gradle.api.artifacts.Dependency 20 | import org.gradle.api.artifacts.ProjectDependency 21 | import org.gradle.api.artifacts.dsl.DependencyHandler 22 | import org.gradle.kotlin.dsl.DependencyHandlerScope 23 | import org.gradle.kotlin.dsl.add 24 | import java.util.* 25 | 26 | fun DependencyHandlerScope.installScenario( 27 | scenarios: Map>, 28 | scenario: String 29 | ) { 30 | if (scenario.isNullOrBlank()) return 31 | println("Installing scenario: '$scenario'") 32 | val trimScenario = if (scenario.endsWith(SCENARIO_DELIMITER) && scenario != SCENARIO_DELIMITER) { 33 | scenario.substringBeforeLast(SCENARIO_DELIMITER) 34 | } else { 35 | scenario 36 | } 37 | installScenario(scenarios, trimScenario.substringBeforeLast(SCENARIO_DELIMITER)) 38 | 39 | scenarios[scenario]?.forEach { dependency -> 40 | if (dependency.startsWith(SCENARIO_DELIMITER)) { 41 | installScenario(scenarios, dependency) 42 | } else { 43 | implementation(dependency) 44 | } 45 | } ?: error("Cannot find the feature flag: '$scenario'") 46 | } 47 | 48 | fun Project.loadScenarioFromLocal(): String { 49 | val props = Properties() 50 | val inputStream = file("${rootDir}/local.properties").inputStream() 51 | 52 | inputStream.use { props.load(it) } 53 | return props["scenario"] as? String ?: DEFAULT_SCENARIO 54 | } 55 | 56 | /** 57 | * Returns the runtime Java class of this object. 58 | */ 59 | @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST") 60 | inline val T.javaClass: Class 61 | @Suppress("UsePropertyAccessSyntax") 62 | get() = (this as java.lang.Object).getClass() as Class 63 | 64 | /** 65 | * Adds a dependency to the 'implementation' configuration. 66 | * 67 | * @param dependencyNotation notation for the dependency to be added. 68 | * @return The dependency. 69 | * 70 | * @see [DependencyHandler.add] 71 | */ 72 | private fun DependencyHandler.implementation(path: Any): Dependency? = 73 | add("implementation", project(mapOf("path" to path)) as ProjectDependency) 74 | 75 | private const val SCENARIO_DELIMITER = ">" 76 | const val DEFAULT_SCENARIO = "${SCENARIO_DELIMITER}default" 77 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/featureflags/Scenario.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package featureflags 17 | 18 | val scenarios = mapOf( 19 | Scenario.default to listOf(Scenario.guidomiaWithDatabase), 20 | Scenario.root to listOf(), 21 | Scenario.guidomia to listOf(Modules.guidomiaImpl), 22 | Scenario.guidomiaWithDatabase to listOf(Modules.databaseImpl) 23 | ) 24 | 25 | private object Scenario { 26 | const val default = DEFAULT_SCENARIO 27 | const val root = ">" 28 | const val guidomia = ">guidomia" 29 | const val guidomiaWithDatabase = ">guidomia>database" 30 | } 31 | -------------------------------------------------------------------------------- /core/impl/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /core/impl/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | id("com.android.library") 18 | kotlin("android") 19 | kotlin("kapt") 20 | id("com.squareup.anvil") version Versions.anvil 21 | } 22 | 23 | configureAndroidLibrary() 24 | 25 | android { 26 | buildFeatures { 27 | viewBinding = true 28 | } 29 | } 30 | 31 | anvil { 32 | generateDaggerFactories = true 33 | } 34 | 35 | dependencies { 36 | implementation(project(Modules.corePublic)) 37 | implementation(project(Modules.diPublic)) 38 | implementation(project(Modules.guidomiaPublic)) 39 | 40 | implementation(Depends.kotlinStdLib) 41 | implementation(Depends.coreKtx) 42 | implementation(Depends.appCompat) 43 | implementation(Depends.material) 44 | implementation(Depends.constraintLayout) 45 | implementation(Depends.dagger) 46 | implementation(Depends.coroutines) 47 | 48 | testImplementation(Depends.junit) 49 | androidTestImplementation(Depends.testExtJunit) 50 | androidTestImplementation(Depends.espressoCore) 51 | } 52 | -------------------------------------------------------------------------------- /core/impl/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/impl/src/main/java/com/hadilq/guidomia/core/impl/DispatcherProviderImpl.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.impl 17 | 18 | import com.hadilq.guidomia.core.api.DispatcherProvider 19 | import com.hadilq.guidomia.di.api.AppScope 20 | import com.squareup.anvil.annotations.ContributesBinding 21 | import kotlinx.coroutines.CoroutineDispatcher 22 | import kotlinx.coroutines.Dispatchers 23 | import javax.inject.Inject 24 | 25 | @ContributesBinding(AppScope::class) 26 | class DispatcherProviderImpl @Inject constructor() : DispatcherProvider { 27 | 28 | override val Main: CoroutineDispatcher 29 | get() = Dispatchers.Main 30 | 31 | override val Default: CoroutineDispatcher 32 | get() = Dispatchers.Default 33 | 34 | override val IO: CoroutineDispatcher 35 | get() = Dispatchers.IO 36 | } -------------------------------------------------------------------------------- /core/impl/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/public/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /core/public/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | plugins { 17 | id("com.android.library") 18 | kotlin("android") 19 | } 20 | 21 | configureAndroidLibrary() 22 | 23 | android { 24 | buildFeatures { 25 | viewBinding = true 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation(Depends.kotlinStdLib) 31 | implementation(Depends.material) 32 | implementation(Depends.dagger) 33 | implementation(Depends.viewModel) 34 | } 35 | -------------------------------------------------------------------------------- /core/public/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/DispatcherProvider.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import kotlinx.coroutines.CoroutineDispatcher 19 | 20 | interface DispatcherProvider { 21 | val Main: CoroutineDispatcher 22 | val Default: CoroutineDispatcher 23 | val IO: CoroutineDispatcher 24 | } -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/FragmentFactory.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.fragment.app.Fragment 19 | import kotlin.reflect.KClass 20 | 21 | interface FragmentFactory { 22 | 23 | fun instantiate(clazz: KClass): Fragment 24 | } 25 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.fragment.app.Fragment 19 | import dagger.MapKey 20 | import kotlin.reflect.KClass 21 | 22 | @MustBeDocumented 23 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) 24 | @Retention(AnnotationRetention.RUNTIME) 25 | @MapKey 26 | annotation class FragmentKey(val value: KClass) 27 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/SimpleFragmentFactory.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.fragment.app.Fragment 19 | 20 | interface SimpleFragmentFactory { 21 | 22 | fun instantiate(): Fragment 23 | } 24 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/SimpleViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.lifecycle.ViewModel 19 | 20 | interface SimpleViewModelFactory { 21 | 22 | fun create(): ViewModel 23 | } 24 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/ViewBinding.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import android.os.Looper 19 | import androidx.lifecycle.Lifecycle 20 | import androidx.lifecycle.LifecycleObserver 21 | import androidx.lifecycle.LifecycleOwner 22 | import androidx.lifecycle.OnLifecycleEvent 23 | import androidx.viewbinding.ViewBinding 24 | import kotlin.properties.ReadOnlyProperty 25 | import kotlin.reflect.KProperty 26 | 27 | fun LifecycleOwner.viewBinding( 28 | initializer: () -> T 29 | ): ReadOnlyProperty = ViewBindingPropertyDelegate(this, initializer) 30 | 31 | class ViewBindingPropertyDelegate( 32 | owner: LifecycleOwner, 33 | private val initializer: () -> T 34 | ) : ReadOnlyProperty, LifecycleObserver { 35 | 36 | private var _value: T? = null 37 | 38 | init { 39 | owner.lifecycle.addObserver(this) 40 | } 41 | 42 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 43 | fun onDestroy() { 44 | _value = null 45 | } 46 | 47 | override fun getValue(thisRef: LifecycleOwner, property: KProperty<*>): T { 48 | if (_value == null) { 49 | 50 | // This must be on the main thread only 51 | if (Looper.myLooper() != Looper.getMainLooper()) { 52 | throw IllegalThreadStateException( 53 | "This cannot be called from other threads. " + 54 | "It should be on the main thread only." 55 | ) 56 | } 57 | 58 | _value = initializer() 59 | } 60 | return _value!! 61 | } 62 | } -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/ViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.lifecycle.ViewModel 19 | import androidx.lifecycle.ViewModelProvider 20 | 21 | interface ViewModelFactory : ViewModelProvider.Factory { 22 | 23 | override fun create(modelClass: Class): T 24 | } 25 | -------------------------------------------------------------------------------- /core/public/src/main/java/com/hadilq/guidomia/core/api/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Hadi Lashkari Ghouchani 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.hadilq.guidomia.core.api 17 | 18 | import androidx.lifecycle.ViewModel 19 | import dagger.MapKey 20 | import kotlin.reflect.KClass 21 | 22 | @MustBeDocumented 23 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) 24 | @Retention(AnnotationRetention.RUNTIME) 25 | @MapKey 26 | annotation class ViewModelKey(val value: KClass) 27 | -------------------------------------------------------------------------------- /core/public/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /core/public/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FC6016 4 | #858585 5 | #D5D5D5 6 | #73000000 7 | #FF000000 8 | #FFFFFFFF 9 | 10 | -------------------------------------------------------------------------------- /core/public/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2dp 4 | 5 | -------------------------------------------------------------------------------- /core/public/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Guidomia 3 | -------------------------------------------------------------------------------- /core/public/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 21 | 22 |