├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .idea ├── .gitignore ├── AndroidProjectSystem.xml ├── appInsightsSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetSelector.xml ├── jarRepositories.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml └── runConfigurations.xml ├── .kotlin └── sessions │ └── kotlin-compiler-15487606082947259740.salive ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── apimorlabs │ │ └── composetemplate │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── com │ │ │ └── apimorlabs │ │ │ └── composetemplate │ │ │ └── app │ │ │ ├── MyApplication.kt │ │ │ ├── datastore │ │ │ ├── DataStoreHelpers.kt │ │ │ └── PrefDataStore.kt │ │ │ ├── di │ │ │ └── KoinMain.kt │ │ │ ├── ui │ │ │ ├── components │ │ │ │ └── Greating.kt │ │ │ ├── main │ │ │ │ └── MainActivity.kt │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ ├── Dimens.kt │ │ │ │ ├── Shape.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── Type.kt │ │ │ └── utils │ │ │ ├── Constants.kt │ │ │ └── Resource.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── animated_icon.xml │ │ ├── branding_image_drawable.xml │ │ ├── branding_image_layer_list.xml │ │ ├── ic_launcher_background.xml │ │ └── vectordrawable.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night-v31 │ │ └── splash_theme.xml │ │ ├── values-night │ │ ├── colors.xml │ │ ├── splash_theme.xml │ │ └── themes.xml │ │ ├── values-v27 │ │ └── themes.xml │ │ ├── values-v31 │ │ └── splash_theme.xml │ │ └── values │ │ ├── colors.xml │ │ ├── splash_theme.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── apimorlabs │ └── composetemplate │ └── ExampleUnitTest.kt ├── build-configs ├── build.gradle.kts ├── checks │ └── detekt.yml ├── gradle.properties ├── plugins │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── com │ │ └── apimorlabs │ │ └── composetemplate │ │ ├── extensions │ │ ├── AndroidExtensions.kt │ │ ├── ComposeExtensions.kt │ │ ├── Kotlin.kt │ │ ├── VersionCatalogExtensions.kt │ │ └── Versions.kt │ │ └── plugins │ │ ├── AndroidAppPlugin.kt │ │ ├── AndroidLibPlugin.kt │ │ └── DetektConventionPlugin.kt ├── proguard-config │ └── proguard-rules.pro └── settings.gradle.kts ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Computer (please complete the following information):** 27 | - OS: [e.g. Windows 10, macOS 11.2.2] 28 | - Android Studio Release [e.g. stable, beta] 29 | - Version [e.g. Arctic Fox 2020.x.x] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | reports/ 18 | build-configs/.kotlin 19 | .kotlin 20 | # Uncomment the following line in case you need and you don't have the release build type files in your app 21 | # release/ 22 | 23 | # Gradle files 24 | .gradle/ 25 | build/ 26 | 27 | # Local configuration file (sdk path, etc) 28 | local.properties 29 | 30 | # Proguard folder generated by Eclipse 31 | proguard/ 32 | 33 | # Log Files 34 | *.log 35 | 36 | # Android Studio Navigation editor temp files 37 | .navigation/ 38 | 39 | # Android Studio captures folder 40 | captures/ 41 | 42 | # IntelliJ 43 | *.iml 44 | .idea/workspace.xml 45 | .idea/tasks.xml 46 | .idea/gradle.xml 47 | .idea/assetWizardSettings.xml 48 | .idea/dictionaries 49 | .idea/libraries 50 | # Android Studio 3 in .gitignore file. 51 | .idea/caches 52 | .idea/modules.xml 53 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 54 | .idea/navEditor.xml 55 | 56 | # Keystore files 57 | *.jks 58 | *.keystore 59 | 60 | # External native build folder generated in Android Studio 2.2 and later 61 | .externalNativeBuild 62 | .cxx/ 63 | 64 | # Google Services (e.g. APIs or Firebase) 65 | google-services.json 66 | 67 | # Freeline 68 | freeline.py 69 | freeline/ 70 | freeline_project_description.json 71 | 72 | # fastlane 73 | fastlane/report.xml 74 | fastlane/Preview.html 75 | fastlane/screenshots 76 | fastlane/test_output 77 | fastlane/readme.md 78 | 79 | # Version control 80 | vcs.xml 81 | 82 | # lint 83 | lint/intermediates/ 84 | lint/generated/ 85 | lint/outputs/ 86 | lint/tmp/ 87 | # lint/reports/ 88 | 89 | #macOS 90 | .DS_Store 91 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 119 | 120 | 122 | 123 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.kotlin/sessions/kotlin-compiler-15487606082947259740.salive: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/.kotlin/sessions/kotlin-compiler-15487606082947259740.salive -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## 🤝 Contributing 2 | 3 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any 4 | contributions you make are **greatly appreciated**. 5 | 6 | 1. Open an issue first to discuss what you would like to change. 7 | 1. Fork the Project 8 | 1. Create your feature branch (`git checkout -b feature/1/amazing-feature`) 9 | 1. Commit your changes (`git commit -m 'Add some amazing feature'`) 10 | 1. Push to the branch (`git push origin feature/1/amazing-feature`) 11 | 1. Open a pull request 12 | 13 | (Here, `1` = issue number) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Racka98 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComposeAndroidTemplate 2 | This is Template repository for Android Jetpack Compose 3 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.apimorlabs.composetemplate.extensions.Versions 2 | 3 | plugins { 4 | alias(libs.plugins.android.app) 5 | alias(libs.plugins.kotlin.serialization) 6 | alias(libs.plugins.kotlin) 7 | } 8 | 9 | android { 10 | namespace = Versions.PACKAGE_NAME + ".app" 11 | kotlinOptions { 12 | jvmTarget = Versions.jvmTarget 13 | } 14 | } 15 | 16 | dependencies { 17 | 18 | // Core Functionality 19 | implementation(libs.androidx.profileinstaller) 20 | implementation(libs.core.ktx) 21 | 22 | // Testing 23 | testImplementation(libs.junit.core) 24 | testImplementation(libs.junit.test) 25 | testImplementation(libs.junit.test.ktx) 26 | androidTestImplementation(libs.junit.test) 27 | 28 | testImplementation(libs.androidx.test.arch.core) 29 | androidTestImplementation(libs.androidx.test.arch.core) 30 | androidTestImplementation(libs.androidx.test.core) 31 | 32 | // Compose 33 | implementation(platform(libs.compose.bom)) 34 | // This is bundle for all common Compose deps 35 | implementation(libs.bundles.compose.core) 36 | implementation(libs.lifecycle.compose.runtime) 37 | 38 | // Testing Compose 39 | //androidTestImplementation(libs.compose.junit) 40 | debugImplementation(libs.compose.tooling) 41 | 42 | // Datastore 43 | implementation(libs.androidx.datastore.preferences) 44 | 45 | // Koin DI 46 | implementation(platform(libs.koin.bom)) 47 | implementation(libs.koin.android) 48 | // Splash Screen 49 | implementation(libs.splash.screen.core) 50 | // Timber - Logging 51 | implementation(libs.timber.log) 52 | 53 | // Memory Leaks 54 | debugImplementation(libs.leakcanary.android) 55 | } 56 | -------------------------------------------------------------------------------- /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. 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/androidTest/java/com/apimorlabs/composetemplate/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.composetemplate 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.composetemplate", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app 2 | 3 | import android.app.Application 4 | import com.apimorlabs.composetemplate.app.di.KoinMain 5 | import com.squareup.leakcanary.core.BuildConfig 6 | import org.koin.android.ext.koin.androidContext 7 | import org.koin.android.ext.koin.androidLogger 8 | import org.koin.core.context.startKoin 9 | import org.koin.core.logger.Level 10 | import timber.log.Timber 11 | 12 | class MyApplication : Application() { 13 | 14 | override fun onCreate() { 15 | super.onCreate() 16 | 17 | startKoin { 18 | // https://github.com/InsertKoinIO/koin/issues/1188 19 | androidLogger(if (BuildConfig.DEBUG) Level.ERROR else Level.NONE) 20 | androidContext(this@MyApplication) 21 | modules(KoinMain.install()) 22 | } 23 | 24 | Timber.plant(Timber.DebugTree()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/datastore/DataStoreHelpers.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.datastore 2 | 3 | import androidx.datastore.core.DataStore 4 | import androidx.datastore.preferences.core.Preferences 5 | import androidx.datastore.preferences.core.edit 6 | import kotlinx.coroutines.flow.Flow 7 | import kotlinx.coroutines.flow.catch 8 | import kotlinx.coroutines.flow.map 9 | import timber.log.Timber 10 | import java.io.IOException 11 | 12 | object DataStoreHelpers { 13 | 14 | suspend fun writePreference( 15 | dataStore: DataStore, 16 | preferenceKey: Preferences.Key, 17 | value: T 18 | ) = dataStore.edit { preferences -> 19 | preferences[preferenceKey] = value 20 | } 21 | 22 | fun readPreference( 23 | dataStore: DataStore, 24 | preferenceKey: Preferences.Key, 25 | defaultValue: T 26 | ): Flow = dataStore.data 27 | .catch { exception -> 28 | if (exception is IOException) { 29 | Timber.d(exception.message.toString()) 30 | } else { 31 | throw exception 32 | } 33 | }.map { preferences -> 34 | preferences[preferenceKey] ?: defaultValue 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/datastore/PrefDataStore.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.datastore 2 | 3 | import android.content.Context 4 | import androidx.datastore.core.DataStore 5 | import androidx.datastore.preferences.core.Preferences 6 | import androidx.datastore.preferences.core.intPreferencesKey 7 | import androidx.datastore.preferences.preferencesDataStore 8 | import com.apimorlabs.composetemplate.app.ui.theme.Theme 9 | import com.apimorlabs.composetemplate.app.utils.Constants 10 | import kotlinx.coroutines.CoroutineDispatcher 11 | import kotlinx.coroutines.CoroutineScope 12 | import kotlinx.coroutines.flow.Flow 13 | 14 | // This is provided by Hilt for easy usage throughout the app 15 | class PrefDataStore( 16 | context: Context, 17 | dispatcher: CoroutineDispatcher 18 | ) { 19 | private object PreferenceKeys { 20 | val themeOption = intPreferencesKey(name = "theme_option") 21 | } 22 | 23 | private val Context.dataStore: DataStore by preferencesDataStore( 24 | name = Constants.PREFERENCE_NAME, 25 | scope = CoroutineScope(dispatcher) 26 | ) 27 | 28 | private val dataStore = context.dataStore 29 | 30 | // Theme Settings 31 | // See Theme enum class inside ui/theme/theme.kt for data meaning 32 | suspend fun saveThemeSetting(value: Int) { 33 | DataStoreHelpers.writePreference( 34 | dataStore, 35 | preferenceKey = PreferenceKeys.themeOption, 36 | value = value 37 | ) 38 | } 39 | 40 | val readThemeSetting: Flow = DataStoreHelpers.readPreference( 41 | dataStore, 42 | preferenceKey = PreferenceKeys.themeOption, 43 | defaultValue = Theme.MATERIAL_YOU.themeValue 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/di/KoinMain.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.di 2 | 3 | import com.apimorlabs.composetemplate.app.datastore.PrefDataStore 4 | import kotlinx.coroutines.Dispatchers 5 | import org.koin.android.ext.koin.androidContext 6 | import org.koin.dsl.module 7 | 8 | object KoinMain { 9 | fun install() = module { 10 | single { 11 | PrefDataStore( 12 | context = androidContext(), 13 | dispatcher = Dispatchers.IO 14 | ) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/components/Greating.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.components 2 | 3 | import androidx.compose.material3.Text 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | import androidx.compose.ui.tooling.preview.Preview 7 | import com.apimorlabs.composetemplate.app.ui.theme.ComposeAndroidTemplateTheme 8 | 9 | @Composable 10 | fun Greeting(name: String, modifier: Modifier = Modifier) { 11 | Text(text = "Hello $name!", modifier = modifier) 12 | } 13 | 14 | @Preview(showBackground = true) 15 | @Composable 16 | fun DefaultPreview() { 17 | ComposeAndroidTemplateTheme { 18 | Greeting("Android") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.main 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material3.MaterialTheme 8 | import androidx.compose.material3.Surface 9 | import androidx.compose.runtime.collectAsState 10 | import androidx.compose.runtime.getValue 11 | import androidx.compose.ui.Modifier 12 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen 13 | import com.apimorlabs.composetemplate.app.datastore.PrefDataStore 14 | import com.apimorlabs.composetemplate.app.ui.components.Greeting 15 | import com.apimorlabs.composetemplate.app.ui.theme.ComposeAndroidTemplateTheme 16 | import com.apimorlabs.composetemplate.app.ui.theme.Theme 17 | import org.koin.android.ext.android.inject 18 | 19 | class MainActivity : ComponentActivity() { 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | // Enable support for Splash Screen API for 23 | // proper Android 12+ support 24 | installSplashScreen() 25 | 26 | val preferences by inject() 27 | setContent { 28 | val themeValue by preferences.readThemeSetting 29 | .collectAsState(initial = Theme.MATERIAL_YOU.themeValue) 30 | 31 | ComposeAndroidTemplateTheme(theme = themeValue) { 32 | // A surface container using the 'background' color from the theme 33 | Surface( 34 | color = MaterialTheme.colorScheme.background, 35 | modifier = Modifier.fillMaxSize() 36 | ) { 37 | Greeting("Compose") 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val PrimaryColor = Color(0xff6167FF) 6 | val PrimaryLightColor = Color(0xffBEC1FF) 7 | val PrimaryDarkColor = Color(0xffb64fc8) 8 | 9 | val SecondaryColor = Color(0xff6167FF) 10 | val SecondaryLightColor = Color(0xffBEC1FF) 11 | val SecondaryDarkColor = Color(0xff6167FF) 12 | 13 | val PrimaryTextColor = Color(0xffffffff) 14 | val SecondaryTextColor = Color(0xff000000) 15 | val SecondaryLightTextColor = Color(0xff000000) 16 | val SecondaryDarkTextColor = Color(0xffffffff) 17 | 18 | val SurfaceDark = Color(0xFF3A3A3A) 19 | val SurfaceVariantDarkTextColor = Color(0xFFCACACA) 20 | val SurfaceLight = Color(0xFFFFFFFF) 21 | val SurfaceVariantLightTextColor = Color(0xFF7A7A7A) 22 | 23 | val BackgroundLightColor = Color(0xffF1F0F5) 24 | val BackgroundDarkColor = Color(0xff121212) 25 | 26 | val ErrorColor = Color(0xFFFF8989) 27 | val OnErrorColor = Color(0xFF000000) 28 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/theme/Dimens.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.theme 2 | 3 | import androidx.compose.ui.unit.Dp 4 | import androidx.compose.ui.unit.dp 5 | 6 | enum class Dimens(val size: Dp) { 7 | ExtraSmallPadding(4.dp), 8 | SmallPadding(8.dp), 9 | MediumPadding(16.dp), 10 | UpperMediumPadding(20.dp), 11 | LargePadding(32.dp), 12 | ExtraLargePadding(64.dp) 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material3.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(20.dp) 11 | ) 12 | 13 | val BottomSheetShape = RoundedCornerShape( 14 | topStart = 20.dp, 15 | topEnd = 20.dp, 16 | bottomStart = 0.dp, 17 | bottomEnd = 0.dp 18 | ) 19 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.theme 2 | 3 | import android.os.Build 4 | import androidx.appcompat.app.AppCompatDelegate 5 | import androidx.compose.foundation.isSystemInDarkTheme 6 | import androidx.compose.material.icons.Icons 7 | import androidx.compose.material.icons.outlined.DarkMode 8 | import androidx.compose.material.icons.outlined.LightMode 9 | import androidx.compose.material.icons.outlined.SettingsSuggest 10 | import androidx.compose.material.icons.outlined.Wallpaper 11 | import androidx.compose.material3.* 12 | import androidx.compose.runtime.Composable 13 | import androidx.compose.ui.graphics.Color 14 | import androidx.compose.ui.graphics.vector.ImageVector 15 | import androidx.compose.ui.platform.LocalContext 16 | 17 | private val AppLightColorScheme = lightColorScheme( 18 | primary = PrimaryColor, 19 | onPrimary = PrimaryTextColor, 20 | secondary = SecondaryColor, 21 | onSecondary = SecondaryTextColor, 22 | tertiary = PrimaryLightColor, 23 | onTertiary = PrimaryTextColor, 24 | background = BackgroundLightColor, 25 | onBackground = Color.Black, 26 | surface = SurfaceLight, 27 | onSurface = Color.Black, 28 | surfaceVariant = SurfaceLight, 29 | onSurfaceVariant = Color.Black, 30 | secondaryContainer = PrimaryColor, 31 | onSecondaryContainer = Color.White, 32 | error = ErrorColor, 33 | onError = OnErrorColor 34 | ) 35 | 36 | private val AppDarkColorScheme = darkColorScheme( 37 | primary = PrimaryColor, 38 | onPrimary = PrimaryTextColor, 39 | secondary = SecondaryLightColor, 40 | onSecondary = SecondaryTextColor, 41 | tertiary = PrimaryLightColor, 42 | onTertiary = PrimaryTextColor, 43 | background = BackgroundDarkColor, 44 | onBackground = Color.White, 45 | surface = SurfaceDark, 46 | onSurface = Color.White, 47 | surfaceVariant = SurfaceDark, 48 | onSurfaceVariant = Color.White, 49 | secondaryContainer = PrimaryColor, 50 | onSecondaryContainer = Color.White, 51 | error = ErrorColor, 52 | onError = OnErrorColor 53 | ) 54 | 55 | @Composable 56 | fun ComposeAndroidTemplateTheme( 57 | theme: Int = Theme.MATERIAL_YOU.themeValue, 58 | content: @Composable () -> Unit 59 | ) { 60 | val autoColors = if (isSystemInDarkTheme()) AppDarkColorScheme else AppLightColorScheme 61 | 62 | val dynamicColors = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 63 | val context = LocalContext.current 64 | if (isSystemInDarkTheme()) { 65 | dynamicDarkColorScheme(context) 66 | } else { 67 | dynamicLightColorScheme(context) 68 | } 69 | } else { 70 | autoColors 71 | } 72 | 73 | val colors = when (theme) { 74 | Theme.LIGHT_THEME.themeValue -> AppLightColorScheme 75 | Theme.DARK_THEME.themeValue -> AppDarkColorScheme 76 | Theme.MATERIAL_YOU.themeValue -> dynamicColors 77 | else -> autoColors 78 | } 79 | 80 | MaterialTheme( 81 | colorScheme = colors, 82 | typography = Typography, 83 | // shapes = Shapes, 84 | content = content 85 | ) 86 | } 87 | 88 | // To be used to set the preferred theme inside settings 89 | enum class Theme( 90 | val themeName: String, 91 | val icon: ImageVector, 92 | val themeValue: Int 93 | ) { 94 | MATERIAL_YOU( 95 | themeName = "Material You", 96 | icon = Icons.Outlined.Wallpaper, 97 | themeValue = 12 98 | ), 99 | FOLLOW_SYSTEM( 100 | themeName = "Follow System Settings", 101 | icon = Icons.Outlined.SettingsSuggest, 102 | themeValue = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM 103 | ), 104 | LIGHT_THEME( 105 | themeName = "Light Theme", 106 | icon = Icons.Outlined.LightMode, 107 | themeValue = AppCompatDelegate.MODE_NIGHT_NO 108 | ), 109 | DARK_THEME( 110 | themeName = "Dark Theme", 111 | icon = Icons.Outlined.DarkMode, 112 | themeValue = AppCompatDelegate.MODE_NIGHT_YES 113 | ) 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontWeight 6 | import androidx.compose.ui.unit.sp 7 | 8 | // Set of Material3 typography styles to start with 9 | val Typography = Typography( 10 | headlineLarge = TextStyle( 11 | fontWeight = FontWeight.Normal, 12 | fontSize = 30.sp, 13 | lineHeight = 38.sp 14 | ), 15 | headlineMedium = TextStyle( 16 | fontWeight = FontWeight.Normal, 17 | fontSize = 24.sp, 18 | lineHeight = 32.sp 19 | ), 20 | headlineSmall = TextStyle( 21 | fontWeight = FontWeight.Normal, 22 | fontSize = 22.sp, 23 | lineHeight = 30.sp 24 | ), 25 | bodyLarge = TextStyle( 26 | fontWeight = FontWeight.Normal, 27 | fontSize = 16.sp 28 | ), 29 | bodyMedium = TextStyle( 30 | fontWeight = FontWeight.Normal, 31 | fontSize = 14.sp 32 | ), 33 | titleLarge = TextStyle( 34 | fontWeight = FontWeight.Medium, 35 | fontSize = 18.sp 36 | ), 37 | titleMedium = TextStyle( 38 | fontWeight = FontWeight.Normal, 39 | fontSize = 16.sp 40 | ), 41 | labelLarge = TextStyle( 42 | fontWeight = FontWeight.Medium, 43 | fontSize = 14.sp, 44 | lineHeight = 20.sp 45 | ), 46 | labelMedium = TextStyle( 47 | fontWeight = FontWeight.Medium, 48 | fontSize = 12.sp, 49 | lineHeight = 16.sp 50 | ), 51 | labelSmall = TextStyle( 52 | fontWeight = FontWeight.Medium, 53 | fontSize = 11.sp, 54 | lineHeight = 6.sp 55 | ), 56 | /* Other default text styles to override 57 | button = TextStyle( 58 | fontFamily = FontFamily.Default, 59 | fontWeight = FontWeight.W500, 60 | fontSize = 14.sp 61 | ), 62 | caption = TextStyle( 63 | fontFamily = FontFamily.Default, 64 | fontWeight = FontWeight.Normal, 65 | fontSize = 12.sp 66 | ) 67 | */ 68 | ) 69 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/utils/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.utils 2 | 3 | object Constants { 4 | const val PREFERENCE_NAME = "settings_preference" 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/kotlin/com/apimorlabs/composetemplate/app/utils/Resource.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.app.utils 2 | 3 | // Use this for handling data from network calls 4 | sealed class Resource( 5 | val data: T? = null, 6 | val message: String? = null 7 | ) { 8 | class Success(data: T) : Resource(data = data) 9 | 10 | class Error( 11 | message: String, 12 | data: T? = null 13 | ) : Resource(message = message, data = data) 14 | 15 | class Loading(data: T? = null) : Resource(data) 16 | } 17 | -------------------------------------------------------------------------------- /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/animated_icon.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 17 | 22 | 23 | 29 | 34 | 37 | 38 | 44 | 47 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 92 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/branding_image_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/branding_image_layer_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /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/drawable/vectordrawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 15 | 19 | 20 | 21 | 22 | 23 | * 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /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.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night-v31/splash_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #99606060 4 | #CCFFFFFF 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/splash_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values-v27/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/values-v31/splash_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | 9 | #FF000000 10 | #FFFFFFFF 11 | #FF1E1E1E 12 | 13 | #ea80fc 14 | #ffb2ff 15 | #b64fc8 16 | #ff80ab 17 | #ffb2dd 18 | #c94f7c 19 | #000000 20 | #000000 21 | 22 | #99dddddd 23 | #1E1E1E 24 | -------------------------------------------------------------------------------- /app/src/main/res/values/splash_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ComposeAndroidTemplate 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/test/java/com/apimorlabs/composetemplate/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * See [testing documentation](http://d.android.com/tools/testing). 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | assertEquals(4, 2 + 2) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /build-configs/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } -------------------------------------------------------------------------------- /build-configs/checks/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 | warningsAsErrors: false 13 | checkExhaustiveness: false 14 | # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' 15 | excludes: '' 16 | 17 | processors: 18 | active: true 19 | exclude: 20 | - 'DetektProgressListener' 21 | # - 'KtFileCountProcessor' 22 | # - 'PackageCountProcessor' 23 | # - 'ClassCountProcessor' 24 | # - 'FunctionCountProcessor' 25 | # - 'PropertyCountProcessor' 26 | # - 'ProjectComplexityProcessor' 27 | # - 'ProjectCognitiveComplexityProcessor' 28 | # - 'ProjectLLOCProcessor' 29 | # - 'ProjectCLOCProcessor' 30 | # - 'ProjectLOCProcessor' 31 | # - 'ProjectSLOCProcessor' 32 | # - 'LicenseHeaderLoaderExtension' 33 | 34 | console-reports: 35 | active: true 36 | exclude: 37 | - 'ProjectStatisticsReport' 38 | - 'ComplexityReport' 39 | - 'NotificationReport' 40 | - 'FindingsReport' 41 | - 'FileBasedFindingsReport' 42 | # - 'LiteFindingsReport' 43 | 44 | output-reports: 45 | active: true 46 | exclude: 47 | # - 'TxtOutputReport' 48 | # - 'XmlOutputReport' 49 | # - 'HtmlOutputReport' 50 | # - 'MdOutputReport' 51 | 52 | comments: 53 | active: true 54 | AbsentOrWrongFileLicense: 55 | active: false 56 | licenseTemplateFile: 'license.template' 57 | licenseTemplateIsRegex: false 58 | CommentOverPrivateFunction: 59 | active: false 60 | CommentOverPrivateProperty: 61 | active: false 62 | DeprecatedBlockTag: 63 | active: false 64 | EndOfSentenceFormat: 65 | active: false 66 | endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' 67 | KDocReferencesNonPublicProperty: 68 | active: false 69 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 70 | OutdatedDocumentation: 71 | active: false 72 | matchTypeParameters: true 73 | matchDeclarationsOrder: true 74 | allowParamOnConstructorProperties: false 75 | UndocumentedPublicClass: 76 | active: false 77 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 78 | searchInNestedClass: true 79 | searchInInnerClass: true 80 | searchInInnerObject: true 81 | searchInInnerInterface: true 82 | searchInProtectedClass: false 83 | UndocumentedPublicFunction: 84 | active: false 85 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 86 | searchProtectedFunction: false 87 | UndocumentedPublicProperty: 88 | active: false 89 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 90 | searchProtectedProperty: false 91 | 92 | complexity: 93 | active: true 94 | ComplexCondition: 95 | active: true 96 | threshold: 10 97 | ComplexInterface: 98 | active: false 99 | threshold: 10 100 | includeStaticDeclarations: false 101 | includePrivateDeclarations: false 102 | ignoreOverloaded: false 103 | CyclomaticComplexMethod: 104 | active: false # Because of Jetpack Compose functions 105 | threshold: 15 106 | ignoreSingleWhenExpression: true 107 | ignoreSimpleWhenEntries: true 108 | ignoreNestingFunctions: true 109 | nestingFunctions: 110 | - 'also' 111 | - 'apply' 112 | - 'forEach' 113 | - 'isNotNull' 114 | - 'ifNull' 115 | - 'let' 116 | - 'run' 117 | - 'use' 118 | - 'with' 119 | LabeledExpression: 120 | active: false 121 | ignoredLabels: [] 122 | LargeClass: 123 | active: true 124 | threshold: 600 125 | LongMethod: 126 | active: true 127 | threshold: 300 128 | LongParameterList: 129 | active: true 130 | functionThreshold: 25 # Because of Jetpack Compose 131 | constructorThreshold: 10 132 | ignoreDefaultParameters: true 133 | ignoreDataClasses: true 134 | ignoreAnnotatedParameter: [ 'Composable', 'Preview', 'Stable' ] 135 | ignoreAnnotated: [ 'Stable' ] 136 | MethodOverloading: 137 | active: false 138 | threshold: 6 139 | NamedArguments: 140 | active: false 141 | threshold: 3 142 | ignoreArgumentsMatchingNames: false 143 | NestedBlockDepth: 144 | active: false 145 | threshold: 4 146 | NestedScopeFunctions: 147 | active: false 148 | threshold: 1 149 | functions: 150 | - 'kotlin.apply' 151 | - 'kotlin.run' 152 | - 'kotlin.with' 153 | - 'kotlin.let' 154 | - 'kotlin.also' 155 | ReplaceSafeCallChainWithRun: 156 | active: false 157 | StringLiteralDuplication: 158 | active: false 159 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 160 | threshold: 3 161 | ignoreAnnotation: true 162 | excludeStringsWithLessThan5Characters: true 163 | ignoreStringsRegex: '$^' 164 | TooManyFunctions: 165 | active: true 166 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 167 | thresholdInFiles: 20 168 | thresholdInClasses: 20 169 | thresholdInInterfaces: 20 170 | thresholdInObjects: 20 171 | thresholdInEnums: 10 172 | ignoreDeprecated: true 173 | ignorePrivate: true 174 | ignoreOverridden: false 175 | 176 | coroutines: 177 | active: true 178 | GlobalCoroutineUsage: 179 | active: false 180 | InjectDispatcher: 181 | active: true 182 | dispatcherNames: 183 | - 'IO' 184 | - 'Default' 185 | - 'Unconfined' 186 | RedundantSuspendModifier: 187 | active: true 188 | SleepInsteadOfDelay: 189 | active: true 190 | SuspendFunWithCoroutineScopeReceiver: 191 | active: false 192 | SuspendFunWithFlowReturnType: 193 | active: true 194 | 195 | empty-blocks: 196 | active: true 197 | EmptyCatchBlock: 198 | active: true 199 | allowedExceptionNameRegex: '_|(ignore|expected).*' 200 | EmptyClassBlock: 201 | active: true 202 | EmptyDefaultConstructor: 203 | active: true 204 | EmptyDoWhileBlock: 205 | active: true 206 | EmptyElseBlock: 207 | active: true 208 | EmptyFinallyBlock: 209 | active: true 210 | EmptyForBlock: 211 | active: true 212 | EmptyFunctionBlock: 213 | active: true 214 | ignoreOverridden: false 215 | EmptyIfBlock: 216 | active: true 217 | EmptyInitBlock: 218 | active: true 219 | EmptyKtFile: 220 | active: true 221 | EmptySecondaryConstructor: 222 | active: true 223 | EmptyTryBlock: 224 | active: true 225 | EmptyWhenBlock: 226 | active: true 227 | EmptyWhileBlock: 228 | active: true 229 | 230 | exceptions: 231 | active: true 232 | ExceptionRaisedInUnexpectedLocation: 233 | active: true 234 | methodNames: 235 | - 'equals' 236 | - 'finalize' 237 | - 'hashCode' 238 | - 'toString' 239 | InstanceOfCheckForException: 240 | active: true 241 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 242 | NotImplementedDeclaration: 243 | active: false 244 | ObjectExtendsThrowable: 245 | active: false 246 | PrintStackTrace: 247 | active: true 248 | RethrowCaughtException: 249 | active: true 250 | ReturnFromFinally: 251 | active: true 252 | ignoreLabeled: false 253 | SwallowedException: 254 | active: true 255 | ignoredExceptionTypes: 256 | - 'InterruptedException' 257 | - 'MalformedURLException' 258 | - 'NumberFormatException' 259 | - 'ParseException' 260 | - 'SerializationException' 261 | allowedExceptionNameRegex: '_|(ignore|expected).*' 262 | ThrowingExceptionFromFinally: 263 | active: true 264 | ThrowingExceptionInMain: 265 | active: false 266 | ThrowingExceptionsWithoutMessageOrCause: 267 | active: true 268 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 269 | exceptions: 270 | - 'ArrayIndexOutOfBoundsException' 271 | - 'Exception' 272 | - 'IllegalArgumentException' 273 | - 'IllegalMonitorStateException' 274 | - 'IllegalStateException' 275 | - 'IndexOutOfBoundsException' 276 | - 'NullPointerException' 277 | - 'RuntimeException' 278 | - 'Throwable' 279 | ThrowingNewInstanceOfSameException: 280 | active: true 281 | TooGenericExceptionCaught: 282 | active: false 283 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 284 | exceptionNames: 285 | - 'ArrayIndexOutOfBoundsException' 286 | - 'Error' 287 | - 'Exception' 288 | - 'IllegalMonitorStateException' 289 | - 'IndexOutOfBoundsException' 290 | - 'NullPointerException' 291 | - 'RuntimeException' 292 | - 'Throwable' 293 | allowedExceptionNameRegex: '_|(ignore|expected).*' 294 | TooGenericExceptionThrown: 295 | active: true 296 | exceptionNames: 297 | - 'Error' 298 | - 'Exception' 299 | - 'RuntimeException' 300 | - 'Throwable' 301 | 302 | naming: 303 | active: true 304 | BooleanPropertyNaming: 305 | active: false 306 | allowedPattern: '^(is|has|are)' 307 | ignoreOverridden: true 308 | ClassNaming: 309 | active: true 310 | classPattern: '[A-Z][a-zA-Z0-9]*' 311 | ConstructorParameterNaming: 312 | active: true 313 | parameterPattern: '[a-z][A-Za-z0-9]*' 314 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 315 | excludeClassPattern: '$^' 316 | ignoreOverridden: true 317 | EnumNaming: 318 | active: true 319 | enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' 320 | ForbiddenClassName: 321 | active: false 322 | forbiddenName: [] 323 | FunctionMaxLength: 324 | active: false 325 | maximumFunctionNameLength: 30 326 | FunctionMinLength: 327 | active: false 328 | minimumFunctionNameLength: 3 329 | FunctionNaming: 330 | active: true 331 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 332 | functionPattern: '[a-zA-Z][a-zA-Z0-9]*' 333 | excludeClassPattern: '$^' 334 | ignoreOverridden: true 335 | FunctionParameterNaming: 336 | active: true 337 | parameterPattern: '[a-z][A-Za-z0-9]*' 338 | excludeClassPattern: '$^' 339 | ignoreOverridden: true 340 | InvalidPackageDeclaration: 341 | active: true 342 | rootPackage: '' 343 | requireRootInDeclaration: false 344 | LambdaParameterNaming: 345 | active: false 346 | parameterPattern: '[a-z][A-Za-z0-9]*|_' 347 | MatchingDeclarationName: 348 | # turned off because of compose multiplatform expect/actual naming 349 | # eg. Foo.kt with expect would need Food.android.kt, Food.ios.kt & Food.desktop.kt 350 | # these would all be marked and can be pretty annoying 351 | active: false 352 | mustBeFirst: true 353 | MemberNameEqualsClassName: 354 | active: true 355 | ignoreOverridden: true 356 | NoNameShadowing: 357 | active: true 358 | NonBooleanPropertyPrefixedWithIs: 359 | active: false 360 | ObjectPropertyNaming: 361 | active: true 362 | constantPattern: '[A-Za-z][_A-Za-z0-9]*' 363 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 364 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' 365 | PackageNaming: 366 | active: true 367 | packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' 368 | TopLevelPropertyNaming: 369 | active: true 370 | constantPattern: '[A-Za-z][_A-Za-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 | maximumVariableNameLength: 64 376 | VariableMinLength: 377 | active: false 378 | minimumVariableNameLength: 1 379 | VariableNaming: 380 | active: true 381 | variablePattern: '[a-z][A-Za-z0-9]*' 382 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' 383 | excludeClassPattern: '$^' 384 | ignoreOverridden: true 385 | 386 | performance: 387 | active: true 388 | ArrayPrimitive: 389 | active: true 390 | CouldBeSequence: 391 | active: false 392 | threshold: 3 393 | ForEachOnRange: 394 | active: true 395 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 396 | SpreadOperator: 397 | active: true 398 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 399 | UnnecessaryPartOfBinaryExpression: 400 | active: false 401 | UnnecessaryTemporaryInstantiation: 402 | active: true 403 | 404 | potential-bugs: 405 | active: true 406 | AvoidReferentialEquality: 407 | active: true 408 | forbiddenTypePatterns: 409 | - 'kotlin.String' 410 | CastToNullableType: 411 | active: false 412 | Deprecation: 413 | active: false 414 | DontDowncastCollectionTypes: 415 | active: false 416 | DoubleMutabilityForCollection: 417 | active: true 418 | mutableTypes: 419 | - 'kotlin.collections.MutableList' 420 | - 'kotlin.collections.MutableMap' 421 | - 'kotlin.collections.MutableSet' 422 | - 'java.util.ArrayList' 423 | - 'java.util.LinkedHashSet' 424 | - 'java.util.HashSet' 425 | - 'java.util.LinkedHashMap' 426 | - 'java.util.HashMap' 427 | ElseCaseInsteadOfExhaustiveWhen: 428 | active: false 429 | EqualsAlwaysReturnsTrueOrFalse: 430 | active: true 431 | EqualsWithHashCodeExist: 432 | active: true 433 | ExitOutsideMain: 434 | active: false 435 | ExplicitGarbageCollectionCall: 436 | active: true 437 | HasPlatformType: 438 | active: true 439 | IgnoredReturnValue: 440 | active: true 441 | restrictToConfig: true 442 | returnValueAnnotations: 443 | - '*.CheckResult' 444 | - '*.CheckReturnValue' 445 | ignoreReturnValueAnnotations: 446 | - '*.CanIgnoreReturnValue' 447 | returnValueTypes: 448 | - 'kotlin.sequences.Sequence' 449 | - 'kotlinx.coroutines.flow.*Flow' 450 | - 'java.util.stream.*Stream' 451 | ignoreFunctionCall: [] 452 | ImplicitDefaultLocale: 453 | active: true 454 | ImplicitUnitReturnType: 455 | active: false 456 | allowExplicitReturnType: true 457 | InvalidRange: 458 | active: true 459 | IteratorHasNextCallsNextMethod: 460 | active: true 461 | IteratorNotThrowingNoSuchElementException: 462 | active: true 463 | LateinitUsage: 464 | active: false 465 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 466 | ignoreOnClassesPattern: '' 467 | MapGetWithNotNullAssertionOperator: 468 | active: true 469 | MissingPackageDeclaration: 470 | active: false 471 | excludes: ['**/*.kts'] 472 | NullCheckOnMutableProperty: 473 | active: false 474 | NullableToStringCall: 475 | active: false 476 | UnconditionalJumpStatementInLoop: 477 | active: false 478 | UnnecessaryNotNullCheck: 479 | active: false 480 | UnnecessaryNotNullOperator: 481 | active: true 482 | UnnecessarySafeCall: 483 | active: true 484 | UnreachableCatchBlock: 485 | active: true 486 | UnreachableCode: 487 | active: true 488 | UnsafeCallOnNullableType: 489 | active: true 490 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] 491 | UnsafeCast: 492 | active: true 493 | UnusedUnaryOperator: 494 | active: true 495 | UselessPostfixExpression: 496 | active: true 497 | WrongEqualsTypeParameter: 498 | active: true 499 | 500 | style: 501 | active: true 502 | AlsoCouldBeApply: 503 | active: false 504 | CanBeNonNullable: 505 | active: false 506 | CascadingCallWrapping: 507 | active: false 508 | includeElvis: true 509 | ClassOrdering: 510 | active: false 511 | CollapsibleIfStatements: 512 | active: false 513 | DataClassContainsFunctions: 514 | active: false 515 | conversionFunctionPrefix: 516 | - 'to' 517 | DataClassShouldBeImmutable: 518 | active: false 519 | DestructuringDeclarationWithTooManyEntries: 520 | active: true 521 | maxDestructuringEntries: 3 522 | EqualsNullCall: 523 | active: true 524 | EqualsOnSignatureLine: 525 | active: false 526 | ExplicitCollectionElementAccessMethod: 527 | active: false 528 | ExplicitItLambdaParameter: 529 | active: true 530 | ExpressionBodySyntax: 531 | active: false 532 | includeLineWrapping: false 533 | ForbiddenComment: 534 | active: true 535 | values: 536 | - 'FIXME:' 537 | - 'STOPSHIP:' 538 | #- 'TODO:' 539 | allowedPatterns: '' 540 | customMessage: '' 541 | ForbiddenImport: 542 | active: false 543 | imports: [] 544 | forbiddenPatterns: '' 545 | ForbiddenMethodCall: 546 | active: false 547 | methods: 548 | - reason: 'print does not allow you to configure the output stream. Use a logger instead.' 549 | value: 'kotlin.io.print' 550 | - reason: 'println does not allow you to configure the output stream. Use a logger instead.' 551 | value: 'kotlin.io.println' 552 | ForbiddenSuppress: 553 | active: false 554 | rules: [] 555 | ForbiddenVoid: 556 | active: true 557 | ignoreOverridden: false 558 | ignoreUsageInGenerics: false 559 | FunctionOnlyReturningConstant: 560 | active: true 561 | ignoreOverridableFunction: true 562 | ignoreActualFunction: true 563 | excludedFunctions: [] 564 | LoopWithTooManyJumpStatements: 565 | active: true 566 | maxJumpCount: 1 567 | MagicNumber: 568 | active: false 569 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] 570 | ignoreNumbers: 571 | - '-2' 572 | - '-1' 573 | - '0' 574 | - '1' 575 | - '2' 576 | - '5' 577 | - '10' 578 | ignoreHashCodeFunction: true 579 | ignorePropertyDeclaration: true 580 | ignoreLocalVariableDeclaration: false 581 | ignoreConstantDeclaration: true 582 | ignoreCompanionObjectPropertyDeclaration: true 583 | ignoreAnnotation: false 584 | ignoreNamedArgument: true 585 | ignoreEnums: false 586 | ignoreRanges: false 587 | ignoreExtensionFunctions: true 588 | MandatoryBracesIfStatements: 589 | active: false 590 | MandatoryBracesLoops: 591 | active: false 592 | MaxChainedCallsOnSameLine: 593 | active: false 594 | maxChainedCalls: 5 595 | MaxLineLength: 596 | active: true 597 | maxLineLength: 120 598 | excludePackageStatements: true 599 | excludeImportStatements: true 600 | excludeCommentStatements: false 601 | excludeRawStrings: true 602 | MayBeConst: 603 | active: true 604 | ModifierOrder: 605 | active: true 606 | MultilineLambdaItParameter: 607 | active: false 608 | MultilineRawStringIndentation: 609 | active: false 610 | indentSize: 4 611 | NestedClassesVisibility: 612 | active: true 613 | NewLineAtEndOfFile: 614 | active: true 615 | NoTabs: 616 | active: false 617 | NullableBooleanCheck: 618 | active: false 619 | ObjectLiteralToLambda: 620 | active: true 621 | OptionalAbstractKeyword: 622 | active: true 623 | OptionalUnit: 624 | active: false 625 | OptionalWhenBraces: 626 | active: false 627 | PreferToOverPairSyntax: 628 | active: false 629 | ProtectedMemberInFinalClass: 630 | active: true 631 | RedundantExplicitType: 632 | active: false 633 | RedundantHigherOrderMapUsage: 634 | active: true 635 | RedundantVisibilityModifierRule: 636 | active: false 637 | ReturnCount: 638 | active: true 639 | max: 2 640 | excludedFunctions: 641 | - 'equals' 642 | excludeLabeled: false 643 | excludeReturnFromLambda: true 644 | excludeGuardClauses: false 645 | SafeCast: 646 | active: true 647 | SerialVersionUIDInSerializableClass: 648 | active: true 649 | SpacingBetweenPackageAndImports: 650 | active: false 651 | ThrowsCount: 652 | active: true 653 | max: 4 654 | excludeGuardClauses: false 655 | TrailingWhitespace: 656 | active: false 657 | TrimMultilineRawString: 658 | active: false 659 | UnderscoresInNumericLiterals: 660 | active: false 661 | acceptableLength: 4 662 | allowNonStandardGrouping: false 663 | UnnecessaryAbstractClass: 664 | active: true 665 | UnnecessaryAnnotationUseSiteTarget: 666 | active: false 667 | UnnecessaryApply: 668 | active: true 669 | UnnecessaryBackticks: 670 | active: false 671 | UnnecessaryFilter: 672 | active: true 673 | UnnecessaryInheritance: 674 | active: true 675 | UnnecessaryInnerClass: 676 | active: false 677 | UnnecessaryLet: 678 | active: false 679 | UnnecessaryParentheses: 680 | active: false 681 | allowForUnclearPrecedence: false 682 | UntilInsteadOfRangeTo: 683 | active: false 684 | UnusedImports: 685 | active: false 686 | UnusedPrivateClass: 687 | active: true 688 | UnusedPrivateMember: 689 | active: true 690 | allowedNames: '(_|ignored|expected|serialVersionUID)' 691 | ignoreAnnotated: [ 'Composable', 'Preview' ] 692 | UseAnyOrNoneInsteadOfFind: 693 | active: true 694 | UseArrayLiteralsInAnnotations: 695 | active: true 696 | UseCheckNotNull: 697 | active: true 698 | UseCheckOrError: 699 | active: true 700 | UseDataClass: 701 | active: false 702 | allowVars: false 703 | UseEmptyCounterpart: 704 | active: false 705 | UseIfEmptyOrIfBlank: 706 | active: false 707 | UseIfInsteadOfWhen: 708 | active: false 709 | UseIsNullOrEmpty: 710 | active: true 711 | UseOrEmpty: 712 | active: true 713 | UseRequire: 714 | active: true 715 | UseRequireNotNull: 716 | active: true 717 | UseSumOfInsteadOfFlatMapSize: 718 | active: false 719 | UselessCallOnNotNull: 720 | active: true 721 | UtilityClassWithPublicConstructor: 722 | active: true 723 | VarCouldBeVal: 724 | active: true 725 | ignoreLateinitVar: false 726 | WildcardImport: 727 | active: false 728 | excludeImports: 729 | - 'java.util.*' 730 | 731 | formatting: 732 | NoWildcardImports: 733 | active: false 734 | 735 | TwitterCompose: 736 | CompositionLocalAllowlist: 737 | active: true 738 | # You can optionally define a list of CompositionLocals that are allowed here 739 | # allowedCompositionLocals: LocalSomething,LocalSomethingElse 740 | CompositionLocalNaming: 741 | active: true 742 | ContentEmitterReturningValues: 743 | active: true 744 | # You can optionally add your own composables here 745 | # contentEmitters: MyComposable,MyOtherComposable 746 | ModifierComposable: 747 | active: true 748 | ModifierMissing: 749 | active: true 750 | ModifierReused: 751 | active: true 752 | ModifierWithoutDefault: 753 | active: true 754 | MultipleEmitters: 755 | active: true 756 | # You can optionally add your own composables here 757 | # contentEmitters: MyComposable,MyOtherComposable 758 | MutableParams: 759 | active: true 760 | ComposableNaming: 761 | active: true 762 | # You can optionally disable the checks in this rule for regex matches against the composable name (e.g. molecule presenters) 763 | # allowedComposableFunctionNames: .*Presenter,.*MoleculePresenter 764 | ComposableParamOrder: 765 | active: true 766 | PreviewNaming: 767 | active: true 768 | PreviewPublic: 769 | active: true 770 | # You can optionally disable that only previews with @PreviewParameter are flagged 771 | # previewPublicOnlyIfParams: false 772 | RememberMissing: 773 | active: true 774 | UnstableCollections: 775 | active: true 776 | ViewModelForwarding: 777 | active: true 778 | ViewModelInjection: 779 | active: true -------------------------------------------------------------------------------- /build-configs/gradle.properties: -------------------------------------------------------------------------------- 1 | # Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534 2 | org.gradle.parallel=true 3 | org.gradle.caching=true 4 | org.gradle.configureondemand=true 5 | -------------------------------------------------------------------------------- /build-configs/plugins/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | group = "com.apimorlabs.reluct.plugins" 6 | 7 | java { 8 | sourceCompatibility = JavaVersion.VERSION_11 9 | targetCompatibility = JavaVersion.VERSION_11 10 | 11 | toolchain { 12 | languageVersion.set(JavaLanguageVersion.of(11)) 13 | } 14 | } 15 | 16 | dependencies { 17 | // Dependencies setup here to enable detection of corresponding source files for plugins 18 | compileOnly(libs.android.gradle.plugin) 19 | compileOnly(libs.kotlin.gradle.plugin) 20 | compileOnly(libs.compose.compiler.gradle.plugin) 21 | compileOnly(libs.detekt.gradle.plugin) 22 | } 23 | 24 | gradlePlugin { 25 | // IDs for these custom plugins are obtained from libs.versions.toml for ease of use in project 26 | plugins { 27 | register("detektPlugin") { 28 | id = libs.plugins.detekt.setup.get().pluginId 29 | implementationClass = "com.apimorlabs.composetemplate.plugins.DetektConventionPlugin" 30 | } 31 | register("androidAppPlugin") { 32 | id = libs.plugins.android.app.get().pluginId 33 | implementationClass = "com.apimorlabs.composetemplate.plugins.AndroidAppPlugin" 34 | } 35 | register("androidLibPlugin") { 36 | id = libs.plugins.android.lib.get().pluginId 37 | implementationClass = "com.apimorlabs.composetemplate.plugins.AndroidLibPlugin" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/extensions/AndroidExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.extensions 2 | 3 | import com.android.build.gradle.BaseExtension 4 | import org.gradle.api.Project 5 | import org.gradle.kotlin.dsl.configure 6 | import org.gradle.kotlin.dsl.dependencies 7 | 8 | internal fun Project.configureAndroid() { 9 | android { 10 | compileSdkVersion = "android-${Versions.COMPILE_SDK}" 11 | 12 | defaultConfig { 13 | minSdk = Versions.MIN_SDK 14 | targetSdk = Versions.TARGET_SDK 15 | versionCode = Versions.VERSION_CODE 16 | versionName = Versions.VERSION_NAME 17 | } 18 | 19 | compileOptions { 20 | isCoreLibraryDesugaringEnabled = true 21 | } 22 | 23 | buildFeatures.buildConfig = true 24 | 25 | packagingOptions { 26 | resources { 27 | excludes += mutableSetOf( 28 | "/META-INF/{AL2.0,LGPL2.1}", 29 | "META-INF/licenses/ASM" 30 | ) 31 | // Fixes conflicts caused by ByteBuddy library used in 32 | // coroutines-debug and mockito 33 | pickFirsts += mutableSetOf( 34 | "win32-x86-64/attach_hotspot_windows.dll", 35 | "win32-x86/attach_hotspot_windows.dll" 36 | ) 37 | } 38 | } 39 | } 40 | 41 | dependencies { 42 | add("coreLibraryDesugaring", libs.findLibrary("desugaring").get()) 43 | } 44 | } 45 | 46 | internal fun Project.android(action: BaseExtension.() -> Unit) = 47 | (extensions.findByName("android") as? BaseExtension)?.apply { 48 | configure(action) 49 | } 50 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/extensions/ComposeExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.extensions 2 | 3 | import com.android.build.api.dsl.CommonExtension 4 | import org.gradle.api.Project 5 | import org.gradle.kotlin.dsl.configure 6 | import org.gradle.kotlin.dsl.dependencies 7 | import org.gradle.kotlin.dsl.withType 8 | import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension 9 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 10 | 11 | 12 | internal fun Project.configureAndroidCompose( 13 | commonExtension: CommonExtension<*, *, *, *, *, *>, 14 | ) { 15 | commonExtension.apply { 16 | 17 | compileSdk = Versions.COMPILE_SDK 18 | 19 | defaultConfig { 20 | minSdk = Versions.MIN_SDK 21 | } 22 | 23 | buildFeatures { 24 | compose = true 25 | } 26 | 27 | buildTypes { 28 | getByName("release") { 29 | isMinifyEnabled = true 30 | } 31 | } 32 | 33 | compileOptions.isCoreLibraryDesugaringEnabled = true 34 | 35 | testOptions { 36 | unitTests { 37 | isIncludeAndroidResources = true 38 | } 39 | } 40 | 41 | configureComposeCompiler() 42 | configureKotlinJvm() 43 | 44 | dependencies { 45 | add("coreLibraryDesugaring", libs.findLibrary("desugaring").get()) 46 | } 47 | 48 | tasks.withType().configureEach { 49 | compilerOptions { 50 | freeCompilerArgs.addAll( 51 | listOf( 52 | "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", 53 | "-opt-in=androidx.compose.material.ExperimentalMaterialApi", 54 | "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", 55 | "-opt-in=com.github.takahirom.roborazzi.ExperimentalRoborazziApi", 56 | "-opt-in=dev.chrisbanes.snapper.ExperimentalSnapperApi", 57 | "-opt-in=kotlin.RequiresOptIn", 58 | ) 59 | ) 60 | } 61 | } 62 | } 63 | } 64 | 65 | private fun Project.configureComposeCompiler() { 66 | extensions.configure { 67 | // Needed for Layout Inspector to be able to see all of the nodes in the component tree: 68 | //https://issuetracker.google.com/issues/338842143 69 | includeSourceInformation.set(true) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/extensions/Kotlin.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.extensions 2 | 3 | import com.android.build.gradle.tasks.asJavaVersion 4 | import org.gradle.api.Project 5 | import org.gradle.api.plugins.JavaPluginExtension 6 | import org.gradle.jvm.toolchain.JavaLanguageVersion 7 | import org.gradle.kotlin.dsl.configure 8 | 9 | internal fun Project.configureKotlinJvm() { 10 | extensions.configure { 11 | sourceCompatibility = JavaLanguageVersion.of(Versions.jvmTarget).asJavaVersion() 12 | targetCompatibility = JavaLanguageVersion.of(Versions.jvmTarget).asJavaVersion() 13 | } 14 | 15 | java { 16 | toolchain { 17 | languageVersion.set(JavaLanguageVersion.of(Versions.jvmTarget)) 18 | } 19 | } 20 | } 21 | 22 | private fun Project.java(action: JavaPluginExtension.() -> Unit) = 23 | extensions.configure(action) 24 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/extensions/VersionCatalogExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.extensions 2 | 3 | import org.gradle.api.artifacts.VersionCatalog 4 | import org.gradle.api.Project 5 | import org.gradle.api.artifacts.VersionCatalogsExtension 6 | import org.gradle.kotlin.dsl.getByType 7 | 8 | internal val Project.libs: VersionCatalog 9 | get() = extensions.getByType().named("libs") -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/extensions/Versions.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.extensions 2 | 3 | import org.gradle.api.JavaVersion 4 | 5 | object Versions { 6 | const val COMPILE_SDK = 35 7 | const val MIN_SDK = 26 8 | const val TARGET_SDK = COMPILE_SDK 9 | const val VERSION_CODE = 1 10 | const val VERSION_NAME = "1.0.0" 11 | val PACKAGE_NAME = "com.apimorlabs.composetemplate" 12 | val DESKTOP_VERSION = "1.0.0" 13 | val DESKTOP_PACKAGE_NAME = "ComposeAndroidTemplate" 14 | val jvmTarget: String = JavaVersion.VERSION_17.majorVersion 15 | } 16 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/plugins/AndroidAppPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.plugins 2 | 3 | import com.android.build.api.dsl.ApplicationExtension 4 | import com.apimorlabs.composetemplate.extensions.Versions 5 | import com.apimorlabs.composetemplate.extensions.android 6 | import com.apimorlabs.composetemplate.extensions.configureAndroid 7 | import com.apimorlabs.composetemplate.extensions.configureAndroidCompose 8 | import com.apimorlabs.composetemplate.extensions.libs 9 | import org.gradle.api.Plugin 10 | import org.gradle.api.Project 11 | import org.gradle.kotlin.dsl.configure 12 | import org.gradle.kotlin.dsl.dependencies 13 | import kotlin.jvm.optionals.getOrNull 14 | 15 | /** 16 | * This a plugin setting up the application level of compose multiplatform. 17 | * Will likely be used once per main app module. 18 | */ 19 | class AndroidAppPlugin : Plugin { 20 | override fun apply(target: Project): Unit = with(target) { 21 | with(pluginManager) { 22 | val composeCompiler = libs.findPlugin("compose_compiler").getOrNull()?.orNull 23 | val androidApp = libs.findPlugin("android_application").getOrNull()?.orNull 24 | composeCompiler?.let { plugin -> apply(plugin.pluginId) } 25 | androidApp?.let { plugin -> apply(plugin.pluginId) } 26 | } 27 | 28 | // Android Setup 29 | android { 30 | defaultConfig { 31 | applicationId = Versions.PACKAGE_NAME 32 | targetSdk = Versions.TARGET_SDK 33 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 34 | vectorDrawables { 35 | useSupportLibrary = true 36 | } 37 | } 38 | 39 | buildTypes { 40 | getByName("release") { 41 | isMinifyEnabled = true 42 | isShrinkResources = true 43 | proguardFiles( 44 | getDefaultProguardFile("proguard-android-optimize.txt"), 45 | rootProject.file("build-configs/proguard-config/proguard-rules.pro").absolutePath 46 | ) 47 | } 48 | } 49 | } 50 | 51 | // Configure Android App level 52 | extensions.configure { 53 | 54 | configureAndroid() 55 | configureAndroidCompose(this) 56 | 57 | // Common Dependencies 58 | dependencies { 59 | add("implementation", libs.findLibrary("activity_compose").get()) 60 | add("implementation", libs.findLibrary("appCompat").get()) 61 | add("implementation", libs.findLibrary("core_ktx").get()) 62 | add("implementation", libs.findLibrary("google_material").get()) 63 | add("implementation", libs.findLibrary("splash_screen_core").get()) 64 | add("implementation", libs.findLibrary("viewmodel_core").get()) 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/plugins/AndroidLibPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.plugins 2 | 3 | 4 | import com.android.build.api.dsl.LibraryExtension 5 | import com.apimorlabs.composetemplate.extensions.Versions 6 | import com.apimorlabs.composetemplate.extensions.configureAndroid 7 | import com.apimorlabs.composetemplate.extensions.configureAndroidCompose 8 | import com.apimorlabs.composetemplate.extensions.libs 9 | import org.gradle.api.Plugin 10 | import org.gradle.api.Project 11 | import org.gradle.kotlin.dsl.configure 12 | import org.gradle.kotlin.dsl.dependencies 13 | import kotlin.jvm.optionals.getOrNull 14 | 15 | /** 16 | * This a plugin setting up the library level of Android app. 17 | * To be applied in all library modules that would also contain compose code 18 | */ 19 | class AndroidLibPlugin : Plugin { 20 | override fun apply(target: Project): Unit = with(target) { 21 | with(pluginManager) { 22 | val composeCompiler = libs.findPlugin("compose-compiler").getOrNull()?.orNull 23 | val androidApp = libs.findPlugin("androidLibrary").getOrNull()?.orNull 24 | composeCompiler?.let { plugin -> apply(plugin.pluginId) } 25 | androidApp?.let { plugin -> apply(plugin.pluginId) } 26 | } 27 | 28 | // Android Setup 29 | // Common Dependencies 30 | dependencies { 31 | add("implementation", libs.findLibrary("activity_compose").get()) 32 | add("implementation", libs.findLibrary("appCompat").get()) 33 | add("implementation", libs.findLibrary("core_ktx").get()) 34 | add("implementation", libs.findLibrary("google_material").get()) 35 | add("implementation", libs.findLibrary("splash_screen_core").get()) 36 | add("implementation", libs.findLibrary("viewmodel_core").get()) 37 | } 38 | 39 | // Configure Android Library 40 | extensions.configure { 41 | defaultConfig { 42 | testOptions.targetSdk = Versions.TARGET_SDK 43 | } 44 | 45 | 46 | configureAndroid() 47 | configureAndroidCompose(this) 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /build-configs/plugins/src/main/kotlin/com/apimorlabs/composetemplate/plugins/DetektConventionPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.apimorlabs.composetemplate.plugins 2 | 3 | import com.apimorlabs.composetemplate.extensions.Versions 4 | import io.gitlab.arturbosch.detekt.Detekt 5 | import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask 6 | import io.gitlab.arturbosch.detekt.extensions.DetektExtension 7 | import io.gitlab.arturbosch.detekt.report.ReportMergeTask 8 | import org.gradle.api.Plugin 9 | import org.gradle.api.Project 10 | import org.gradle.kotlin.dsl.apply 11 | import org.gradle.kotlin.dsl.dependencies 12 | import org.gradle.kotlin.dsl.getByType 13 | import org.gradle.kotlin.dsl.withType 14 | import com.apimorlabs.composetemplate.extensions.libs 15 | import kotlin.jvm.optionals.getOrNull 16 | 17 | /** 18 | * This is a convention plugin for Detekt 19 | * To run detekt simply: 20 | * 1. ./gradlew module:detekt for each module 21 | * 2. ./gradlew detekt for whole project 22 | */ 23 | class DetektConventionPlugin : Plugin { 24 | override fun apply(target: Project): Unit = with(target) { 25 | with(pluginManager) { 26 | val detekt = libs.findPlugin("detekt_gradle").getOrNull()?.orNull 27 | detekt?.let { plugin -> apply(plugin.pluginId) } 28 | } 29 | 30 | val detektPlugin = libs.findPlugin("detekt_gradle").getOrNull()?.orNull 31 | 32 | detektPlugin?.run { 33 | apply(plugin = pluginId) 34 | 35 | allprojects { 36 | afterEvaluate { 37 | dependencies { 38 | "detektPlugins"(libs.findLibrary("detekt_formatting").get()) 39 | "detektPlugins"(libs.findLibrary("detekt_rule_twitter_compose").get()) 40 | } 41 | 42 | val detekt = extensions.getByType() 43 | with(detekt) { 44 | buildUponDefaultConfig = true 45 | config.from("$rootDir/build-configs/checks/detekt.yml") 46 | baseline = file("$rootDir/build-configs/checks//baseline.xml") 47 | buildUponDefaultConfig = true 48 | ignoredBuildTypes = listOf("release") 49 | source.from( 50 | DetektExtension.DEFAULT_SRC_DIR_JAVA, 51 | DetektExtension.DEFAULT_TEST_SRC_DIR_JAVA, 52 | DetektExtension.DEFAULT_SRC_DIR_KOTLIN, 53 | DetektExtension.DEFAULT_TEST_SRC_DIR_KOTLIN, 54 | // Kotlin Multiplatform 55 | "src/commonMain/kotlin", 56 | "src/androidMain/kotlin", 57 | "src/iosMain/kotlin", 58 | "src/jvmMain/kotlin", 59 | "src/desktopMain/kotlin", 60 | "src/jsMain/kotlin", 61 | ) 62 | } 63 | 64 | // 65 | tasks.withType().configureEach { 66 | jvmTarget = Versions.jvmTarget 67 | exclude("**/build/**", "**/generated/**", "**/resources/**") 68 | basePath = rootProject.projectDir.absolutePath 69 | autoCorrect = true // Auto corrects common formatting issues 70 | // Configure reports here 71 | reports { 72 | xml.required.set(false) 73 | txt.required.set(false) 74 | md.required.set(false) 75 | 76 | html { 77 | required.set(true) 78 | outputLocation.set( 79 | layout.buildDirectory.file("reports/detekt.html") 80 | ) 81 | } 82 | 83 | sarif.required.set(true) 84 | } 85 | } 86 | 87 | // Report Merge Task 88 | tasks.withType().configureEach { 89 | output.set(layout.projectDirectory.file("reports/detekt/merged_report.sarif")) 90 | input.from(tasks.withType().map { it.reports.sarif.outputLocation }) 91 | } 92 | 93 | // Create Baseline Task 94 | tasks.withType().configureEach { 95 | jvmTarget = Versions.jvmTarget 96 | description = "Overrides current baseline. Used project wide." 97 | buildUponDefaultConfig.set(true) 98 | ignoreFailures.set(true) 99 | parallel.set(true) 100 | setSource(files(rootDir)) 101 | config.setFrom(files("$rootDir/tooling/checks/detekt.yml")) 102 | baseline.set(file("$rootDir/tooling/checks/baseline.xml")) 103 | include("**/*.kt") 104 | include("**/*.kts") 105 | exclude("**/build/**", "**/generated/**", "**/resources/**") 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /build-configs/proguard-config/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 22 | 23 | # Keep `Companion` object fields of serializable classes. 24 | # This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. 25 | -if @kotlinx.serialization.Serializable class ** 26 | -keepclassmembers class <1> { 27 | static <1>$Companion Companion; 28 | } 29 | 30 | # Keep `serializer()` on companion objects (both default and named) of serializable classes. 31 | -if @kotlinx.serialization.Serializable class ** { 32 | static **$* *; 33 | } 34 | -keepclassmembers class <2>$<3> { 35 | kotlinx.serialization.KSerializer serializer(...); 36 | } 37 | 38 | # Keep `INSTANCE.serializer()` of serializable objects. 39 | -if @kotlinx.serialization.Serializable class ** { 40 | public static ** INSTANCE; 41 | } 42 | -keepclassmembers class <1> { 43 | public static <1> INSTANCE; 44 | kotlinx.serialization.KSerializer serializer(...); 45 | } 46 | 47 | # @Serializable and @Polymorphic are used at runtime for polymorphic serialization. 48 | -keepattributes RuntimeVisibleAnnotations,AnnotationDefault 49 | 50 | # Revenuecat classes 51 | -keep class com.revenuecat.purchases.** { *; } 52 | 53 | # Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`. 54 | # If you have any, uncomment and replace classes with those containing named companion objects. 55 | #-keepattributes InnerClasses # Needed for `getDeclaredClasses`. 56 | #-if @kotlinx.serialization.Serializable class 57 | #com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions. 58 | #com.example.myapplication.HasNamedCompanion2 59 | #{ 60 | # static **$* *; 61 | #} 62 | #-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. 63 | # static <1>$$serializer INSTANCE; 64 | #} 65 | 66 | # Coroutines 67 | # ServiceLoader support 68 | -keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} 69 | -keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} 70 | 71 | # Most of volatile fields are updated with AFU and should not be mangled 72 | -keepclassmembers class kotlinx.coroutines.** { 73 | volatile ; 74 | } 75 | 76 | # Same story for the standard library's SafeContinuation that also uses AtomicReferenceFieldUpdater 77 | -keepclassmembers class kotlin.coroutines.SafeContinuation { 78 | volatile ; 79 | } 80 | 81 | # These classes are only required by kotlinx.coroutines.debug.AgentPremain, which is only loaded when 82 | # kotlinx-coroutines-core is used as a Java agent, so these are not needed in contexts where ProGuard is used. 83 | -dontwarn java.lang.instrument.ClassFileTransformer 84 | -dontwarn sun.misc.SignalHandler 85 | -dontwarn java.lang.instrument.Instrumentation 86 | -dontwarn sun.misc.Signal 87 | 88 | # Only used in `kotlinx.coroutines.internal.ExceptionsConstructor`. 89 | # The case when it is not available is hidden in a `try`-`catch`, as well as a check for Android. 90 | -dontwarn java.lang.ClassValue 91 | 92 | # An annotation used for build tooling, won't be directly accessed. 93 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 94 | 95 | # OkHttp 96 | 97 | # JSR 305 annotations are for embedding nullability information. 98 | -dontwarn javax.annotation.** 99 | 100 | # A resource is loaded with a relative path so the package of this class must be preserved. 101 | -adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz 102 | 103 | # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. 104 | -dontwarn org.codehaus.mojo.animal_sniffer.* 105 | 106 | # OkHttp platform used only on JVM and when Conscrypt and other security providers are available. 107 | -dontwarn okhttp3.internal.platform.** 108 | -dontwarn org.conscrypt.** 109 | -dontwarn org.bouncycastle.** 110 | -dontwarn org.openjsse.** -------------------------------------------------------------------------------- /build-configs/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("UnstableApiUsage") 2 | dependencyResolutionManagement { 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | versionCatalogs { 9 | create("libs") { 10 | from(files("../gradle/libs.versions.toml")) 11 | } 12 | } 13 | } 14 | 15 | rootProject.name = "build-configs" 16 | include(":plugins") 17 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | 4 | repositories { 5 | google() 6 | mavenCentral() 7 | gradlePluginPortal() 8 | maven(url = "https://www.jitpack.io") 9 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 10 | } 11 | } 12 | 13 | plugins { 14 | alias(libs.plugins.android.application) apply false 15 | alias(libs.plugins.android.library) apply false 16 | alias(libs.plugins.compose.compiler) apply false 17 | alias(libs.plugins.detekt.gradle) apply false 18 | alias(libs.plugins.detekt.setup) apply false 19 | alias(libs.plugins.sqldelight) apply false 20 | alias(libs.plugins.kotlin.serialization) apply false 21 | alias(libs.plugins.kotlin) apply false 22 | } 23 | 24 | allprojects { 25 | 26 | 27 | afterEvaluate { 28 | apply(plugin = libs.plugins.detekt.setup.get().pluginId) 29 | 30 | // Remove log pollution until Android support in KMP improves. 31 | project.extensions 32 | .findByType() 33 | ?.let { kmpExt -> 34 | kmpExt.sourceSets.removeAll { 35 | setOf( 36 | "androidAndroidTestRelease", 37 | "androidTestFixtures", 38 | "androidTestFixturesDebug", 39 | "androidTestFixturesRelease", 40 | "androidTestFixturesDemo" 41 | ) 42 | .contains(it.name) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=false 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | org.gradle.unsafe.configuration-cache=true 23 | 'org.gradle.unsafe.configuration-cache-problems=warn' 24 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | ##### Dependency Versions Start ######## 2 | [versions] 3 | # App Configs 4 | config_android_minsdk = "23" 5 | config_android_compilesdk = "35" 6 | config_android_targetsdk = "35" 7 | config_android_versioncode = "1" 8 | config_android_versionName = "1.0.0" 9 | config_android_applicationId = "com.example.composetemplate" 10 | 11 | # Important 12 | kotlin = "2.1.20" 13 | android_gradle_plugin = "8.9.1" 14 | 15 | # Kotlin Helpers 16 | kotlinx_date_time = "0.6.2" 17 | kotlinx_coroutines = "1.10.2" 18 | kotlinx_serialization = "1.8.1" 19 | kotlinx_collections_immutable = "0.3.8" 20 | 21 | # Network 22 | ktor = "3.1.2" 23 | 24 | # Android Essentials 25 | activity = "1.10.1" 26 | core_ktx = "1.16.0" 27 | appCompat = "1.7.0" 28 | splash_screen = "1.1.0-rc01" 29 | google_material = "1.12.0" 30 | 31 | # Compose 32 | composeCompiler = "1.5.15" 33 | compose = "2025.04.00" 34 | glance = "1.1.1" 35 | 36 | # Lifecycle 37 | lifecycle = "2.9.0-beta01" 38 | saveState = "1.2.1" 39 | 40 | # Navigation 41 | androidx_navigation = "2.9.0-beta01" 42 | decompose = "3.3.0" 43 | 44 | # DI 45 | koin = "4.0.3" 46 | 47 | # Square (Block) 48 | sqlDelight = "2.0.2" 49 | leakcanary = "3.0-alpha-8" 50 | 51 | # Testing 52 | junit = "4.13.2" 53 | junit_test = "1.2.1" 54 | espresso_test = "3.6.1" 55 | androidx_test_core = "1.6.1" 56 | androidx_test_arch_core = "2.2.0" 57 | androidx_benchmark = "1.3.4" 58 | androidx_uiautomator = "2.3.0" 59 | androidx_profileinstaller = "1.4.1" 60 | 61 | # Helper libs 62 | coil_image = "3.1.0" 63 | accompanist = "0.37.2" 64 | 65 | # Preference 66 | androidx_datastore = "1.1.4" 67 | 68 | # Billing 69 | revenueCat = "8.16.0" 70 | 71 | # Logging 72 | timber = "5.0.1" 73 | slf4j = "1.7.30" 74 | logback = "1.2.3" 75 | kermit = "1.0.0" 76 | 77 | # Linter 78 | ktlint_gradle = "12.1.1" 79 | linter_twitter_compose = "0.0.26" 80 | detekt = "1.23.6" 81 | 82 | # Extras 83 | lottie = "6.4.0" 84 | palette = "1.0.0" 85 | desugaring = "2.1.5" 86 | 87 | # Google Services and Firebase 88 | google_services = "4.4.2" 89 | play_services_auth = "21.3.0" 90 | firebase_bom = "33.12.0" 91 | crashlytics_gradle = "3.0.3" 92 | 93 | ######## Dependency versions End ############# 94 | 95 | 96 | ########### Libraries Start ################## 97 | [libraries] 98 | # Build Plugins (as Classpath) 99 | android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" } 100 | kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } 101 | compose_compiler_gradle_plugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" } 102 | kotlin_serialization_plugin = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } 103 | sqldelight_plugin = { module = "com.squareup.sqldelight:gradle-plugin", version.ref = "sqlDelight" } 104 | google_services_plugin = { module = "com.google.gms:google-services", version.ref = "google_services" } 105 | firebase_crashlytics_plugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version.ref = "crashlytics_gradle" } 106 | 107 | # Kotlin 108 | kotlinx_serialization_core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx_serialization" } 109 | kotlinx_serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx_serialization" } 110 | kotlinx_date_time = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx_date_time" } 111 | kotlinx_collections_immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinx_collections_immutable" } 112 | kotlin_junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } 113 | 114 | coroutines_core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx_coroutines" } 115 | coroutines_android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx_coroutines" } 116 | coroutines_playservices = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinx_coroutines" } 117 | coroutines_test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx_coroutines" } 118 | 119 | # Core & Essentials 120 | activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity" } 121 | core_ktx = { module = "androidx.core:core-ktx", version.ref = "core_ktx" } 122 | appCompat = { module = "androidx.appcompat:appcompat", version.ref = "appCompat" } 123 | google_material = { module = "com.google.android.material:material", version.ref = "google_material" } 124 | splash_screen_core = { module = "androidx.core:core-splashscreen", version.ref = "splash_screen" } 125 | 126 | # Lifecycle 127 | lifecycle_compose_runtime = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" } 128 | viewmodel_core = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" } 129 | viewmodel_compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" } 130 | savedState = { module = "androidx.savedstate:savedstate-ktx", version.ref = "saveState" } 131 | 132 | # Compose 133 | compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose" } 134 | compose_runtime = { module = "androidx.compose.runtime:runtime" } 135 | compose_ui = { module = "androidx.compose.ui:ui" } 136 | compose_foundation = { module = "androidx.compose.foundation:foundation" } 137 | compose_foundation_layout = { module = "androidx.compose.foundation:foundation-layout" } 138 | compose_material = { module = "androidx.compose.material:material" } 139 | compose_material3 = { module = "androidx.compose.material3:material3" } 140 | compose_material_icons_core = { module = "androidx.compose.material:material-icons-core" } 141 | compose_material_icons_extended = { module = "androidx.compose.material:material-icons-extended" } 142 | compose_animation = { module = "androidx.compose.animation:animation" } 143 | compose_preview = { module = "androidx.compose.ui:ui-tooling-preview" } 144 | coil_compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil_image" } 145 | compose_glance = { module = "androidx.glance:glance-appwidget", version.ref = "glance" } 146 | lottie_compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottie" } 147 | 148 | # Compose Testing (As testImplementation or debugImplementation) 149 | compose_junit = { module = "androidx.compose.ui:ui-test-junit4" } 150 | compose_tooling = { module = "androidx.compose.ui:ui-tooling" } 151 | compose_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" } 152 | 153 | # Accompanist 154 | accompanist_nav_animations = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanist" } 155 | accompanist_pager = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanist" } 156 | accompanist_swipe_refresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanist" } 157 | accompanist_system_ui_controller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } 158 | 159 | # Navigation 160 | navigation_compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx_navigation" } 161 | decompose_core = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } 162 | decompose_compose_jb = { module = "com.arkivanov.decompose:extensions-compose-jetbrains", version.ref = "decompose" } 163 | 164 | # DI - Koin 165 | koin_bom = { module = "io.insert-koin:koin-bom", version.ref = "koin"} 166 | koin_core = { module = "io.insert-koin:koin-core" } 167 | koin_android = { module = "io.insert-koin:koin-android" } 168 | koin_android_compose = { module = "io.insert-koin:koin-androidx-compose" } 169 | koin_android_workmanager = { module = "io.insert-koin:koin-androidx-workmanager" } 170 | koin_test = { module = "io.insert-koin:koin-test" } 171 | koin_test_junit = { module = "io.insert-koin:koin-test-junit4" } 172 | 173 | # Testing - JUnit 174 | junit_core = { module = "junit:junit", version.ref = "junit" } 175 | junit_test = { module = "androidx.test.ext:junit", version.ref = "junit_test" } 176 | junit_test_ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junit_test" } 177 | 178 | # Testing - Other 179 | androidx_test_core = { module = "androidx.test:core-ktx", version.ref = "androidx_test_core" } 180 | androidx_test_arch_core = { module = "androidx.arch.core:core-testing", version.ref = "androidx_test_arch_core" } 181 | espresso_core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso_test" } 182 | androidx_benchmark_macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx_benchmark" } 183 | androidx_test_uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx_uiautomator" } 184 | androidx_profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "androidx_profileinstaller" } 185 | 186 | # Helpers and Extras 187 | palette = { module = "androidx.palette:palette-ktx", version.ref = "palette" } 188 | desugaring = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugaring" } 189 | 190 | # Network (KTOR) 191 | ktor_client_core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } 192 | ktor_client_android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" } 193 | ktor_client_okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } 194 | ktor_client_content_negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } 195 | ktor_client_serialization = { module = "io.ktor:ktor-client-serialization", version.ref = "ktor" } 196 | ktor_client_serialization_json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } 197 | ktor_client_logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } 198 | 199 | # Billing 200 | revenueCat_android = { module = "com.revenuecat.purchases:purchases", version.ref = "revenueCat" } 201 | 202 | # Persistence 203 | androidx_datastore_preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx_datastore" } 204 | 205 | # Firebase 206 | firebase_bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase_bom" } 207 | firebase_analytics = { module = "com.google.firebase:firebase-analytics-ktx" } 208 | firebase_crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" } 209 | firebase_auth = { module = "com.google.firebase:firebase-auth-ktx" } 210 | playservices_auth = { module = "com.google.android.gms:play-services-auth", version.ref = "play_services_auth" } 211 | 212 | # Square (Block) 213 | sqldelight_runtime = { module = "com.squareup.sqldelight:runtime", version.ref = "sqlDelight" } 214 | sqldelight_coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqlDelight" } 215 | sqldelight_android_driver = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqlDelight" } 216 | sqldelight_sqlite_driver = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqlDelight" } 217 | leakcanary_android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } 218 | 219 | # Logging 220 | slf4j_simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } 221 | logback_classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } 222 | kermit_log = { module = "co.touchlab:kermit", version.ref = "kermit" } 223 | timber_log = { module = "com.jakewharton.timber:timber", version.ref = "timber" } 224 | 225 | # Linter 226 | detekt_gradle_plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } 227 | detekt_formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } 228 | ktlint_gradle_plugin = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlint_gradle" } 229 | ktlint_rule_twitter_compose = { module = "com.twitter.compose.rules:ktlint", version.ref = "linter_twitter_compose" } 230 | detekt_rule_twitter_compose = { module = "com.twitter.compose.rules:detekt", version.ref = "linter_twitter_compose" } 231 | 232 | ########### Libraries End ################## 233 | 234 | 235 | ############# Bundles Start ################## 236 | [bundles] 237 | # Bundles that can be used together 238 | android_core = ["core.ktx", "appCompat"] 239 | compose_core = ["compose.ui", "compose.runtime", "compose.foundation", "compose.foundation.layout", 240 | "compose.material3", "compose.material.icons.core", "compose.material.icons.extended", 241 | "compose.animation", "compose.preview", "coil.compose", "activity.compose", "compose.tooling.preview", 242 | "kotlinx.collections.immutable"] 243 | 244 | ############# Bundles End ################## 245 | 246 | 247 | ########### Plugnis Start ################## 248 | [plugins] 249 | # All Plugins should stay here 250 | android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" } 251 | android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" } 252 | kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } 253 | compose_compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } 254 | kotlin_serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } 255 | ktlint_gradle = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint_gradle" } 256 | detekt_gradle = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"} 257 | sqldelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" } 258 | 259 | ## Gradle Convention custom plugins 260 | detekt-setup = { id = "plugin.template.detekt.setup" } 261 | android-app = { id = "plugin.template.compose.android.app" } 262 | android-lib = { id = "plugin.template.compose.android.lib" } 263 | 264 | ########### Plugnis END ################## 265 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racka98/ComposeAndroidTemplate/37df1ff6f3d38a79c07538be5259ea2cdb0802af/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Jun 09 22:45:21 EAT 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "ComposeAndroidTemplate" 2 | include(":app") 3 | 4 | pluginManagement { 5 | includeBuild("build-configs") 6 | repositories { 7 | google { 8 | mavenContent { 9 | includeGroupAndSubgroups("androidx") 10 | includeGroupAndSubgroups("com.android") 11 | includeGroupAndSubgroups("com.google") 12 | } 13 | } 14 | mavenCentral() 15 | gradlePluginPortal() 16 | maven(url = "https://www.jitpack.io") 17 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 18 | } 19 | } 20 | 21 | dependencyResolutionManagement { 22 | repositories { 23 | google { 24 | mavenContent { 25 | includeGroupAndSubgroups("androidx") 26 | includeGroupAndSubgroups("com.android") 27 | includeGroupAndSubgroups("com.google") 28 | } 29 | } 30 | mavenCentral() 31 | maven(url = "https://www.jitpack.io") 32 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 33 | maven(url = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") 34 | maven(url = "https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven") 35 | } 36 | } 37 | --------------------------------------------------------------------------------