Skip to content

Commit

Permalink
Allow usage of material TextButton inside of Material AlertDialog wit…
Browse files Browse the repository at this point in the history
…hout lint reporting the usage.

As it now contradicts the other rule to use material components in material dialog.
  • Loading branch information
Alexander Matečný committed Sep 25, 2023
1 parent a12b165 commit 01c73c5
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 01c73c5

Please sign in to comment.