diff --git a/.idea/.gitignore b/.idea/.gitignore index 26d3352..8f00030 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,3 +1,5 @@ # Default ignored files /shelf/ /workspace.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index d7dd1e6..3f7e759 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -2,6 +2,9 @@ + + + diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 0fc3113..e805548 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 814188a..8fb5e7f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,7 +2,8 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.kotlinAndroid) - id("com.google.devtools.ksp") version "1.8.10-1.0.9" + id("com.google.devtools.ksp") version "1.9.21-1.0.15" +// id("com.google.devtools.ksp") version "1.8.10-1.0.9" } android { @@ -40,13 +41,19 @@ android { compose = true } composeOptions { - kotlinCompilerExtensionVersion = "1.4.3" + kotlinCompilerExtensionVersion = "1.5.5" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + tasks.withType { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:experimentalStrongSkipping=true", + ) + } } dependencies { diff --git a/app/src/main/java/dev/sagar/composeperformance/module/ModuleExample.kt b/app/src/main/java/dev/sagar/composeperformance/module/ModuleExample.kt index ca3e328..4977c40 100644 --- a/app/src/main/java/dev/sagar/composeperformance/module/ModuleExample.kt +++ b/app/src/main/java/dev/sagar/composeperformance/module/ModuleExample.kt @@ -1,5 +1,7 @@ package dev.sagar.composeperformance.module +import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -7,7 +9,6 @@ import androidx.compose.material3.Checkbox import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -27,6 +28,12 @@ import dev.sagar.domain.ContactInfo * 3. Enable the Compose compiler and make the data classes stable using the Stable annotation(s). * However it will just be the dependency for the compose runtime and not for Compose-UI. */ + +//data class ContactInfo( +// val name: Int, +// val number: Int, +//) +@RequiresApi(Build.VERSION_CODES.O) @Composable @Destination fun ModuleExample() { @@ -34,13 +41,15 @@ fun ModuleExample() { var isChecked by remember { mutableStateOf(false) } + val contact = ContactInfo(name = 123, number = 1234567890) +// val contact = LocalTime.of(12, 12, 12, 12) Column( modifier = Modifier ) { Checkbox(checked = isChecked, onCheckedChange = { isChecked = it }) - ContactModule(contact = ContactInfo(name = "Sagar", number = 1234567890)) + ContactModuleTesting(contact = contact) } } @@ -48,11 +57,13 @@ fun ModuleExample() { // ISSUE: Composable is taking a data class which is in a seperate module. The Compose compiler // cannot infer the stability of this class. As such it declares it as unstable. @Composable -private fun ContactModule(contact: ContactInfo) { +fun ContactModuleTesting(contact: ContactInfo) { Column { - Text(text = contact.name) +// Text(text = contact.name.toString()) + Text(text = contact.toString()) Spacer(modifier = Modifier.height(8.dp)) - Text(text = "${contact.number}") +// Text(text = "${contact.number}") +// Text(text = "${contact.number}") } } diff --git a/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityExample.kt b/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityExample.kt index 352227c..2fc988b 100644 --- a/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityExample.kt +++ b/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityExample.kt @@ -22,20 +22,21 @@ import com.ramcosta.composedestinations.annotation.Destination * SOLUTION: * 1. Make your param as "val" instead of "var */ + +val contactSimple = ContactInfo(name = "Sagar", number = 1234567890) @Composable @Destination fun RuntimeStabilityExample() { var isChecked by remember { mutableStateOf(false) } - val contact = ContactInfo(name = "Sagar", number = 1234567890) Column( modifier = Modifier ) { Checkbox(checked = isChecked, onCheckedChange = { isChecked = it }) - Contact(contact = contact) + Contact(contact = contactSimple) } } @@ -49,7 +50,7 @@ private fun Contact(contact: ContactInfo) { } // ISSUE: Params are defined as "var" which means it's mutable, and can be changed at runtime. -private data class ContactInfo( +data class ContactInfo( var name: String, var number: Int, ) diff --git a/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityFix.kt b/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityFix.kt index a1ac417..2e3d418 100644 --- a/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityFix.kt +++ b/app/src/main/java/dev/sagar/composeperformance/runtimestability/RuntimeStabilityFix.kt @@ -14,13 +14,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.ramcosta.composedestinations.annotation.Destination +val contact = ContactInfoFix(name = "Sagar", number = 1234567890) @Composable @Destination fun RuntimeStabilityFix() { var isChecked by remember { mutableStateOf(false) } - val contact = ContactInfoFix(name = "Sagar", number = 1234567890) Column( modifier = Modifier ) { @@ -41,7 +41,7 @@ private fun Contact(contact: ContactInfoFix) { } // Solution: Params are defined as "val" which means it's immutable, and makes the runtime stability stable -private data class ContactInfoFix( +data class ContactInfoFix( val name: String, val number: Int, ) diff --git a/build.gradle.kts b/build.gradle.kts index 214e499..82666a8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,18 +9,20 @@ true // Needed to make the Suppress annotation work for the plugins block subprojects { tasks.withType().configureEach { kotlinOptions { - if (project.findProperty("enableComposeCompilerReports") == "true") { - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + - project.buildDir.absolutePath + "/compose_compiler" - ) - } + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + + project.buildDir.absolutePath + "/compose_compiler" + ) freeCompilerArgs += listOf( "-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + project.buildDir.absolutePath + "/compose_compiler" ) + freeCompilerArgs += listOf( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=$rootDir/config/compose_compiler_config.conf", + ) } } } diff --git a/config/compose_compiler_config.conf b/config/compose_compiler_config.conf new file mode 100644 index 0000000..9381984 --- /dev/null +++ b/config/compose_compiler_config.conf @@ -0,0 +1,8 @@ +// This file contains classes (with possible wildcards) that the Compose Compiler will treat as stable. +// It allows us to define classes that our not part of our codebase without wrapping them in a stable class. +// For more information, check https://developer.android.com/jetpack/compose/performance/stability/fix#configuration-file +kotlin.collections.List +kotlin.collections.Set +kotlin.collections.Map +java.time.LocalTime +dev.sagar.domain.ContactInfo diff --git a/domain/src/main/java/dev/sagar/domain/ContactInfo.kt b/domain/src/main/java/dev/sagar/domain/ContactInfo.kt index e32755e..b8af757 100644 --- a/domain/src/main/java/dev/sagar/domain/ContactInfo.kt +++ b/domain/src/main/java/dev/sagar/domain/ContactInfo.kt @@ -1,6 +1,6 @@ package dev.sagar.domain data class ContactInfo( - val name: String, + val name: Int, val number: Int, ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 947bc3a..9b70cba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -agp = "8.3.0-alpha02" -kotlin = "1.8.10" +agp = "8.3.0" +kotlin = "1.9.20" core-ktx = "1.9.0" junit = "4.13.2" androidx-test-ext-junit = "1.1.5" @@ -14,6 +14,8 @@ material = "1.9.0" kotlinx-collections-immutable = "0.3.4" compose-viewmodel = "2.6.1" coroutines-core = "1.7.3" +compose-lint-checks = "1.2.0" +compose-destinations = "1.9.52" [libraries] core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } @@ -37,6 +39,10 @@ kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotli compose-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "compose-viewmodel" } coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines-core" } +compose-lint-checks = { module = "com.slack.lint.compose:compose-lint-checks", version.ref = "compose-lint-checks" } +compose-destinations-core = { module = "io.github.raamcosta.compose-destinations:compose-destinations-core", version.ref = "compose-destinations" } +compose-destinations-ksp = { module = "io.github.raamcosta.compose-destinations:compose-destinations-ksp", version.ref = "compose-destinations" } + [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 82a1003..2618748 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Aug 18 18:15:27 CEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists