Skip to content

Commit

Permalink
Merge pull request #542 from kiwicom/task/exception_to_material_textb…
Browse files Browse the repository at this point in the history
…utton_lint_rule_for_alert_dialogs

Allow usage of material TextButton inside of Material AlertDialog without lint reporting the usage.
  • Loading branch information
hrach authored Sep 26, 2023
2 parents a12b165 + 01c73c5 commit 104fc5a
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package kiwi.orbit.compose.catalog.screens

import android.annotation.SuppressLint
import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
Expand All @@ -13,7 +12,6 @@ internal fun DialogsMaterialDialog(navController: NavController) {
)
}

@SuppressLint("MaterialDesignInsteadOrbitDesign")
@Composable
private fun DialogsMaterialDialog(
onClose: () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.intellij.psi.PsiMember
import com.intellij.psi.impl.source.PsiClassReferenceType
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.uast.UCallExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.USimpleNameReferenceExpression
import org.jetbrains.uast.getContainingUClass
import org.jetbrains.uast.toUElement
import org.jetbrains.uast.tryResolveNamed

class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
Expand All @@ -29,9 +34,24 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne
override fun visitCallExpression(node: UCallExpression) {
val name = node.methodName ?: return
val wrapperName = node.resolve()?.containingClass?.qualifiedName ?: return
val packageName = wrapperName.substring(0, wrapperName.lastIndexOf("."))
val packageName = getPackageName(wrapperName)
val fqn = "$packageName.$name"
val (preferredName) = METHOD_NAMES.entries.firstOrNull { it.value.contains(fqn) } ?: return

// check the potential violation against our allowlist
val allowedEntry = METHOD_ALLOWLIST_IN_PARENT.entries.find { it.key.contains(fqn) }
if (allowedEntry != null) {
val parentExpression = node.sourcePsi?.parents?.find { it is KtCallExpression }
val resolved = parentExpression.toUElement()?.tryResolveNamed()
val parentName = resolved?.name
val parentWrapper = resolved.toUElement()?.getContainingUClass()?.qualifiedName ?: ""
val parentPackage = getPackageName(parentWrapper)
val parentFqn = "$parentPackage.$parentName"
if (allowedEntry.value.find { parentFqn.contains(it) } != null) {
return
}
}

reportIssue(context, node, "$packageName.$name", preferredName)
}

Expand Down Expand Up @@ -66,6 +86,17 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne
),
)

private val METHOD_ALLOWLIST_IN_PARENT = mapOf(
"androidx.compose.material.TextButton" to setOf(
"androidx.compose.material.AlertDialog",
"androidx.compose.material3.AlertDialog",
),
"androidx.compose.material3.TextButton" to setOf(
"androidx.compose.material.AlertDialog",
"androidx.compose.material3.AlertDialog",
),
)

private val METHOD_NAMES = mapOf(
"kiwi.orbit.compose.ui.controls.ButtonPrimary" to setOf(
"androidx.compose.material.Button",
Expand Down Expand Up @@ -191,5 +222,9 @@ class MaterialDesignInsteadOrbitDesignDetector : Detector(), Detector.UastScanne
"Using $name instead of $preferredName",
)
}

private fun getPackageName(fullyQualifiedName: String): String {
return fullyQualifiedName.substring(0, fullyQualifiedName.lastIndexOf("."))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import java.io.File
import org.junit.Assert
import org.junit.Test

@Suppress("UnstableApiUsage")
class MaterialDesignInsteadOrbitDesignDetectorTest {
@Test
fun testDetector() {
Expand All @@ -25,9 +24,11 @@ class MaterialDesignInsteadOrbitDesignDetectorTest {
import androidx.compose.material.contentColorFor
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card as Card3
import androidx.compose.material3.contentColorFor as contentColorFor3
import androidx.compose.material3.Text as Text3
import androidx.compose.material3.TextButton
import androidx.compose.material3.Divider
import androidx.compose.material3.LocalTextStyle
fun Test() {
Expand All @@ -43,7 +44,9 @@ class MaterialDesignInsteadOrbitDesignDetectorTest {
LocalTextStyle.current
LocalTextStyle
LocalTextStyle.provides()
}
AlertDialog(confirmButton = { TextButton("test") })
}
AlertDialog(confirmButton = { TextButton("test") })
}
""".trimIndent(),
)
Expand All @@ -52,6 +55,7 @@ class MaterialDesignInsteadOrbitDesignDetectorTest {
package androidx.compose.material
fun Card(content: () -> Unit) {}
fun Text(content: () -> Unit) {}
fun TextButton(content: String) {}
fun contentColorFor(backgroundColor: Color): Color = TODO()
""".trimIndent(),
)
Expand All @@ -60,7 +64,12 @@ class MaterialDesignInsteadOrbitDesignDetectorTest {
package androidx.compose.material3
fun Card(content: () -> Unit) {}
fun Text(content: () -> Unit) {}
fun TextButton(content: String) {}
fun Divider() {}
fun AlertDialog(
confirmButton: () -> Unit,
dismissButton: (() -> Unit)? = null,
) {}
fun contentColorFor(backgroundColor: Color): Color = TODO()
@Stable
sealed class CompositionLocal<T> constructor(defaultFactory: () -> T) {
Expand Down

0 comments on commit 104fc5a

Please sign in to comment.