Skip to content

Commit

Permalink
Cleanup accessibility colors for compose snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
geoff-powell committed Mar 27, 2023
1 parent 059e7a0 commit d8ef57a
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 68 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,13 @@
*/
package app.cash.paparazzi.accessibility

import android.content.Context
import android.graphics.drawable.GradientDrawable
import android.util.TypedValue
import AccessibilityRowView
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import app.cash.paparazzi.RenderExtension
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_DESCRIPTION_BACKGROUND_COLOR
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_RECT_SIZE
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_TEXT_COLOR
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_TEXT_SIZE
import app.cash.paparazzi.accessibility.RenderSettings.getColor
import app.cash.paparazzi.accessibility.RenderSettings.toColorInt

class AccessibilityRenderExtension : RenderExtension {
Expand Down Expand Up @@ -72,12 +65,15 @@ class AccessibilityRenderExtension : RenderExtension {
)
)

val accessibilityRowViews = mutableListOf<AccessibilityRowView>()
val accessibilityLegend = LinearLayout(context).apply {
orientation = LinearLayout.VERTICAL
setBackgroundColor(DEFAULT_DESCRIPTION_BACKGROUND_COLOR.toColorInt())

accessibilityState.elements.forEach {
addView(buildAccessibilityRow(context, it))
accessibilityState.elements.forEach { _ ->
accessibilityRowViews += AccessibilityRowView(context).also { rowView ->
addView(rowView)
}
}
}
addView(
Expand All @@ -96,70 +92,22 @@ class AccessibilityRenderExtension : RenderExtension {
overlay.addElements(
accessibilityState.elements.map {
AccessibilityOverlayView.AccessibilityElement(
color = getColor(it.id),
color = it.color,
bounds = it.displayBounds
)
}
)
true
}
}
}

private fun buildAccessibilityRow(
context: Context,
element: AccessibilityState.Element
): View {
val color = getColor(element.id).toColorInt()
val margin = context.dip(8)
val innerMargin = context.dip(4)

return LinearLayout(context).apply {
orientation = LinearLayout.HORIZONTAL
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setPaddingRelative(margin, innerMargin, margin, innerMargin)

addView(
View(context).apply {
layoutParams = ViewGroup.LayoutParams(
context.dip(DEFAULT_RECT_SIZE),
context.dip(
DEFAULT_RECT_SIZE
)
)
background = GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(color, color)
).apply {
cornerRadius = context.dip(DEFAULT_RECT_SIZE / 4f)
}
setPaddingRelative(innerMargin, innerMargin, innerMargin, innerMargin)
require(accessibilityState.elements.size == accessibilityRowViews.size) {
"Accessibility state has changed since accessibility state was captured in measureView() - " +
"expected ${accessibilityState.elements.size} elements, but found ${accessibilityRowViews.size} elements."
}
)
addView(
TextView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
text = element.renderString()
textSize = DEFAULT_TEXT_SIZE
setTextColor(DEFAULT_TEXT_COLOR.toColorInt())
setPaddingRelative(innerMargin, 0, innerMargin, 0)
accessibilityState.elements.forEachIndexed { index, element ->
accessibilityRowViews[index].updateForElement(element)
}
)

true
}
}
}
}

private fun Context.dip(value: Float): Float =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
value,
resources.displayMetrics
)

private fun Context.dip(value: Int): Int = dip(value.toFloat()).toInt()
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import app.cash.paparazzi.accessibility.AccessibilityState
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_RECT_SIZE
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_TEXT_COLOR
import app.cash.paparazzi.accessibility.RenderSettings.DEFAULT_TEXT_SIZE
import app.cash.paparazzi.accessibility.RenderSettings.toColorInt

class AccessibilityRowView(context: Context) : LinearLayout(context) {

private val textView: TextView
private val badgeView: View
private val badgeDrawable: GradientDrawable

init {
val margin = context.dip(8)
val innerMargin = context.dip(4)

orientation = HORIZONTAL
layoutParams = LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
)
setPaddingRelative(margin, innerMargin, margin, innerMargin)

badgeView = View(context).apply {
layoutParams = ViewGroup.LayoutParams(
context.dip(DEFAULT_RECT_SIZE),
context.dip(DEFAULT_RECT_SIZE)
)

// Evaluate the color after the view has been measured. This is necessary for compose element ids to be set, which drives element colors.
// val color = accessibilityState.elements[index].color.toColorInt()
badgeDrawable = GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(Color.WHITE, Color.WHITE) // Initial Color.WHITE values are overwritten by the color set in the AccessibilityOverlayView
).apply {
cornerRadius = context.dip(DEFAULT_RECT_SIZE / 4f)
}
setPaddingRelative(innerMargin, innerMargin, innerMargin, innerMargin)
background = badgeDrawable
}

textView = TextView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
textSize = DEFAULT_TEXT_SIZE
setTextColor(DEFAULT_TEXT_COLOR.toColorInt())
setPaddingRelative(innerMargin, 0, innerMargin, 0)
}

addView(badgeView)
addView(textView)
}

fun updateForElement(element: AccessibilityState.Element) {
badgeDrawable.setColor(element.color.toColorInt())
textView.text = element.renderString()
}
}

private fun Context.dip(value: Float): Float =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
value,
resources.displayMetrics
)

private fun Context.dip(value: Int): Int = dip(value.toFloat()).toInt()
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ data class AccessibilityState(
val customActions: List<CustomAction>? = null,
val progress: Progress? = null
) {
val color by lazy { RenderSettings.getColor(id) }

fun renderString() =
text?.joinToString(", ") ?: contentDescription?.joinToString(", ") ?: stateDescription ?: onClickLabel ?: role
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import javax.imageio.ImageIO

class AccessibilityRenderExtensionTest {
private val snapshotHandler = TestSnapshotVerifier()
private val accessibilityRenderExtension = AccessibilityRenderExtension()

@get:Rule
val paparazzi = Paparazzi(
Expand All @@ -33,7 +34,7 @@ class AccessibilityRenderExtensionTest {
softButtons = false
),
snapshotHandler = snapshotHandler,
renderExtensions = setOf(AccessibilityRenderExtension())
renderExtensions = setOf(accessibilityRenderExtension)
)

@Test
Expand Down

0 comments on commit d8ef57a

Please sign in to comment.