Skip to content

Commit

Permalink
ANDROID-14530 Fix checkbox colors (#344)
Browse files Browse the repository at this point in the history
* ANDROID-14530 Fix checkbox compose colors and add tests

* ANDROID-14530 Fix checkbox xml colors

* Updated screenshots baseline

* ANDROID-14530 Fix typo

---------

Co-authored-by: yamal-alm <[email protected]>
  • Loading branch information
yamal-alm and yamal-alm authored Apr 15, 2024
1 parent ae4939d commit 2eb07ca
Show file tree
Hide file tree
Showing 201 changed files with 298 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ fun Inputs() {
TextAreaInputSample()
Title("Check Box input")
CheckBoxInputSample()
DisableCheckBoxInputSample(isChecked = true)
DisableCheckBoxInputSample(isChecked = false)
Title("Dropdown")
DropDownSample()
Title("Disable Dropdown")
Expand Down Expand Up @@ -385,6 +387,22 @@ fun CheckBoxInputSample() {
)
}

@Composable
fun DisableCheckBoxInputSample(
isChecked: Boolean,
) {
CheckBoxInput(
checked = isChecked,
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp, start = 16.dp, end = 16.dp),
text = "This is a disabled checkbox",
enabled = false,
errorText = null,
onCheckedChange = { },
)
}

@Composable
private fun DropDownSample(enabled: Boolean = true) {
val items = remember {
Expand Down
8 changes: 8 additions & 0 deletions catalog/src/main/res/layout/screen_inputs_catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,14 @@
app:inputCheckText="This is a disabled CheckBox"
app:inputEnabled="false"/>

<com.telefonica.mistica.input.CheckBoxInput
android:id="@+id/disabled_checkboxInput_unchecked"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:inputCheckText="This is a disabled CheckBox"
app:inputChecked="false"
app:inputEnabled="false"/>

</LinearLayout>

<com.telefonica.mistica.title.TitleView
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 @@ -5,13 +5,16 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material.Checkbox
import androidx.compose.material.CheckboxDefaults
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.LocalMinimumTouchTargetEnforcement
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.telefonica.mistica.compose.theme.MisticaTheme
import com.telefonica.mistica.compose.ui.alpha

@OptIn(ExperimentalMaterialApi::class)
@Composable
Expand All @@ -25,13 +28,24 @@ fun CheckBoxInput(
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit = {},
) {
Column(modifier = modifier) {
Column(
modifier = modifier.alpha(enabled)
) {
Row {
CompositionLocalProvider(LocalMinimumTouchTargetEnforcement provides false) {
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
enabled = enabled,
colors = CheckboxDefaults.colors(
checkedColor = MisticaTheme.colors.controlActivated,
uncheckedColor = MisticaTheme.colors.control,
disabledColor = if (checked) {
MisticaTheme.colors.controlActivated
} else {
MisticaTheme.colors.control
}
)
)
}
Spacer(modifier = Modifier.width(8.dp))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.telefonica.mistica.input

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.method.MovementMethod
Expand All @@ -12,6 +13,7 @@ import androidx.appcompat.widget.AppCompatCheckBox
import androidx.databinding.*
import com.google.android.material.textfield.TextInputLayout
import com.telefonica.mistica.R
import com.telefonica.mistica.util.getThemeColor

@BindingMethods(
BindingMethod(
Expand Down Expand Up @@ -74,6 +76,7 @@ class CheckBoxInput @JvmOverloads constructor(
setChecked(initialInputChecked)
setText(initialInputText)
configureErrorResetOnCheckChange()
setButtonTint()

return findViewById(R.id.text_input_layout)
}
Expand All @@ -85,6 +88,18 @@ class CheckBoxInput @JvmOverloads constructor(
}
}

private fun setButtonTint() {
val states = arrayOf(
intArrayOf(android.R.attr.state_checked),
intArrayOf(-android.R.attr.state_checked),
)
val colors = intArrayOf(
context.getThemeColor(R.attr.colorControlActive),
context.getThemeColor(R.attr.colorControl),
)
checkBox.buttonTintList = ColorStateList(states, colors)
}

fun setChecked(checked: Boolean) {
checkBox.isChecked = checked
}
Expand Down
14 changes: 2 additions & 12 deletions library/src/test/java/com/telefonica/mistica/button/ButtonTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.telefonica.mistica.compose.theme.brand.TelefonicaBrand
import com.telefonica.mistica.compose.theme.brand.TuBrand
import com.telefonica.mistica.compose.theme.brand.VivoBrand
import com.telefonica.mistica.testutils.ScreenshotsTest
import com.telefonica.mistica.testutils.TestUtils
import com.telefonica.mistica.testutils.TestUtils.getAllBrands
import com.telefonica.mistica.testutils.TestUtils.isInverse
import com.telefonica.mistica.util.getThemeColor
Expand All @@ -37,7 +38,7 @@ internal class ButtonTest(
) : ScreenshotsTest() {

private val intent = Intent(ApplicationProvider.getApplicationContext(), DummyActivity::class.java).apply {
this.putExtra(EXTRA_THEME, brand.getBaseThemeForBrand())
this.putExtra(EXTRA_THEME, TestUtils.getBaseThemeForBrand(brand))
}

@get:Rule
Expand Down Expand Up @@ -105,17 +106,6 @@ internal class ButtonTest(
}
}

@StyleRes
private fun Brand.getBaseThemeForBrand(): Int = when (this) {
MovistarBrand -> R.style.MisticaTheme_Movistar
VivoBrand -> R.style.MisticaTheme_Vivo
O2Brand -> R.style.MisticaTheme_O2
BlauBrand -> R.style.MisticaTheme_Blau
TuBrand -> R.style.MisticaTheme_Tu
TelefonicaBrand -> R.style.MisticaTheme_Telefonica
else -> error("No tests defined for brand $this")
}

@LayoutRes
private fun ButtonStyle.getButtonLayout(): Int = when (this) {
ButtonStyle.PRIMARY -> R.layout.primary_button
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.telefonica.mistica.compose.input

import androidx.compose.foundation.layout.padding
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.unit.dp
import com.telefonica.mistica.compose.theme.MisticaTheme
import com.telefonica.mistica.compose.theme.brand.Brand
import com.telefonica.mistica.testutils.ScreenshotsTest
import com.telefonica.mistica.testutils.TestUtils
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.ParameterizedRobolectricTestRunner.Parameters

@RunWith(ParameterizedRobolectricTestRunner::class)
class CheckBoxInputTest(
private val brand: Brand,
private val checked: Boolean,
private val isEnabled: Boolean,
private val errorText: String?,
private val darkTheme: Boolean,
) : ScreenshotsTest() {
@get:Rule
val composeTestRule = createComposeRule()

@Test
fun `CheckBoxInput compose screenshot`() {
composeTestRule.setContent {
MisticaTheme(brand = brand, darkTheme = darkTheme) {
Surface(
color = MisticaTheme.colors.background
) {
CheckBoxInput(
modifier = Modifier.padding(16.dp),
text = "Some text with terms and conditions",
links = listOf(
TextLink(link = "terms and conditions", onLinkTapped = {}),
),
checked = checked,
onCheckedChange = {},
errorText = errorText,
enabled = isEnabled,
)
}
}
}

val screenshotSuffix = StringBuilder()
if (errorText != null) {
screenshotSuffix.append("_errorText")
}
if (!isEnabled) {
screenshotSuffix.append("_disabled")
}

if (checked) {
screenshotSuffix.append("_checked")
} else {
screenshotSuffix.append("_unchecked")
}

compareScreenshot(
node = composeTestRule.onRoot(),
component = "CheckBoxInput",
style = null,
brand = brand,
darkTheme = darkTheme,
extra = screenshotSuffix.toString()
)
}

companion object {
@Suppress("UNUSED")
@JvmStatic
@Parameters
fun brands(): List<Array<Any?>> {
val brands = TestUtils.getAllBrands()
val enabled = arrayOf(false, true)
val checked = arrayOf(false, true)
val errorTexts = arrayOf(null, "Some error text")
val darkTheme = arrayOf(false, true)

return brands.flatMap { brand ->
enabled.flatMap { isEnabled ->
checked.flatMap { isChecked ->
errorTexts.flatMap { errorText ->
darkTheme.map { darkTheme ->
arrayOf(brand, isEnabled, isChecked, errorText, darkTheme)
}
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.telefonica.mistica.input

import android.content.Intent
import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.view.View
import android.widget.FrameLayout
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.rules.activityScenarioRule
import com.telefonica.mistica.DummyActivity
import com.telefonica.mistica.R
import com.telefonica.mistica.compose.theme.brand.Brand
import com.telefonica.mistica.testutils.ScreenshotsTest
import com.telefonica.mistica.testutils.TestUtils
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.annotation.Config

@RunWith(ParameterizedRobolectricTestRunner::class)
class CheckBoxInputTest(
private val brand: Brand,
private val checked: Boolean,
private val isEnabled: Boolean,
private val errorText: String?,
) : ScreenshotsTest() {
private val intent = Intent(ApplicationProvider.getApplicationContext(), DummyActivity::class.java).apply {
this.putExtra(DummyActivity.EXTRA_THEME, TestUtils.getBaseThemeForBrand(brand))
}

@get:Rule
val rule = activityScenarioRule<DummyActivity>(intent)

@Test
fun `CheckBoxInput XML screenshot light`() {
`compare CheckBoxInput XML screenshot`(darkTheme = false)
}

@Config(qualifiers = "+night")
@Test
fun `CheckBoxInput XML screenshot dark`() {
`compare CheckBoxInput XML screenshot`(darkTheme = true)
}

private fun `compare CheckBoxInput XML screenshot`(darkTheme: Boolean) {
rule.scenario.onActivity { activity ->
val wrapper: FrameLayout = activity.findViewById(R.id.dummy_activity_wrapper)
val checkbox = CheckBoxInput(activity).apply {
setChecked(checked)
error = errorText
setText(createSpannableText())
setMovementMethod(LinkMovementMethod.getInstance())
isEnabled = this@CheckBoxInputTest.isEnabled
}

wrapper.removeAllViews()
wrapper.addView(checkbox)

val screenshotSuffix = StringBuilder()
if (errorText != null) {
screenshotSuffix.append("_errorText")
}
if (!isEnabled) {
screenshotSuffix.append("_disabled")
}

if (checked) {
screenshotSuffix.append("_checked")
} else {
screenshotSuffix.append("_unchecked")
}

compareScreenshot(
node = Espresso.onView(ViewMatchers.withId(R.id.dummy_activity_wrapper)),
component = "CheckBoxInputXML",
style = null,
brand = brand,
darkTheme = darkTheme,
extra = screenshotSuffix.toString()
)
}
}

private fun createSpannableText(): Spannable {
val termsAndConditions = "terms and conditions"
val message = "Some text with $termsAndConditions"
return SpannableString(message).apply {
setSpan(dummyClickableSpan, message.indexOf(termsAndConditions), message.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}

companion object {
@Suppress("UNUSED")
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters
fun brands(): List<Array<Any?>> {
val brands = TestUtils.getAllBrands()
val enabled = arrayOf(false, true)
val checked = arrayOf(false, true)
val errorTexts = arrayOf(null, "Some error text")

return brands.flatMap { brand ->
enabled.flatMap { isEnabled ->
checked.flatMap { isChecked ->
errorTexts.map { errorText ->
arrayOf(brand, isEnabled, isChecked, errorText)
}
}
}
}
}

private val dummyClickableSpan = object : ClickableSpan() { override fun onClick(widget: View) {} }
}
}
Loading

0 comments on commit 2eb07ca

Please sign in to comment.