From b760ce2af47ec1878b8663fcac0a5de31b901d1d Mon Sep 17 00:00:00 2001 From: Jose Rubio Date: Tue, 26 Dec 2023 12:59:46 +0100 Subject: [PATCH] ANDROID-14134 Set assets clickable (#324) * set assets clickable * ANDROID-14134 Update icon size * ANDROID-14134 Revert update icon size * ANDROID-14134 remove space * ANDROID-14134 remove unused parameter * ANDROID-14134 add clickable row examples --- .../components/ListsCatalogFragment.kt | 36 ++++++++++++ .../catalog/ui/compose/components/Lists.kt | 55 +++++++++++++++++++ .../layout/screen_fragment_lists_catalog.xml | 19 +++++++ .../mistica/compose/list/ListRowIcon.kt | 16 ++++-- .../mistica/compose/shape/Circle.kt | 3 +- .../telefonica/mistica/list/ListRowView.kt | 4 ++ .../mistica/compose/list/ListRowItemKtTest.kt | 26 ++++++++- .../mistica/list/ListRowViewTest.kt | 17 ++++++ .../test/res/layout/test_list_row_view.xml | 4 ++ 9 files changed, 173 insertions(+), 7 deletions(-) diff --git a/catalog/src/main/java/com/telefonica/mistica/catalog/ui/classic/components/ListsCatalogFragment.kt b/catalog/src/main/java/com/telefonica/mistica/catalog/ui/classic/components/ListsCatalogFragment.kt index eef476668..4404ac1bb 100644 --- a/catalog/src/main/java/com/telefonica/mistica/catalog/ui/classic/components/ListsCatalogFragment.kt +++ b/catalog/src/main/java/com/telefonica/mistica/catalog/ui/classic/components/ListsCatalogFragment.kt @@ -50,6 +50,9 @@ class ListsCatalogFragment : Fragment() { val boxedInverseList: MisticaRecyclerView = view.findViewById(R.id.boxed_inverse_list) boxedInverseList.adapter = ListAdapter(backgroundType = ListRowView.BackgroundType.TYPE_BOXED_INVERSE) + + val clickableRow: MisticaRecyclerView = view.findViewById(R.id.clickable_list) + clickableRow.adapter = ClickableListAdapter() } class ListAdapter( @@ -553,6 +556,39 @@ class ListsCatalogFragment : Fragment() { class ListViewHolder(val rowView: ListRowView) : RecyclerView.ViewHolder(rowView) + class ClickableListAdapter : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder { + return ListViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.screen_fragment_lists_catalog_item, + parent, + false + ) as ListRowView + ) + } + + override fun getItemCount(): Int = 2 + + override fun onBindViewHolder(holder: ListViewHolder, position: Int) { + with(holder.rowView) { + if (position == 0) { + setTitle("Clickable Asset") + setAssetOnClickListener { + Toast.makeText(context, "Asset clicked!", Toast.LENGTH_SHORT).show() + } + } else { + setTitle("Clickable Asset in Clickable Row") + setOnClickListener { + Toast.makeText(context, "Row clicked!", Toast.LENGTH_SHORT).show() + } + setAssetOnClickListener { + Toast.makeText(context, "Asset clicked!", Toast.LENGTH_SHORT).show() + } + } + } + } + } + private companion object { const val IMAGE_URL = "https://www.fotoaparat.cz/imgs/a/26/2639/0n1wjdf0-cr-em13-09-1200x627x9.jpg" } diff --git a/catalog/src/main/java/com/telefonica/mistica/catalog/ui/compose/components/Lists.kt b/catalog/src/main/java/com/telefonica/mistica/catalog/ui/compose/components/Lists.kt index 9d1e918c4..f636424e6 100644 --- a/catalog/src/main/java/com/telefonica/mistica/catalog/ui/compose/components/Lists.kt +++ b/catalog/src/main/java/com/telefonica/mistica/catalog/ui/compose/components/Lists.kt @@ -1,8 +1,11 @@ package com.telefonica.mistica.catalog.ui.compose.components +import android.content.Context +import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -13,6 +16,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.MaterialTheme import androidx.compose.material.Switch import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -23,6 +27,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest import coil.transform.CircleCropTransformation @@ -298,10 +303,14 @@ const val IMAGE_URL = "https://www.fotoaparat.cz/imgs/a/26/2639/0n1wjdf0-cr-em13 @Composable fun Lists() { val samples = samples() + val context = LocalContext.current LazyColumn( modifier = Modifier .fillMaxSize(), ) { + item { + SectionTitle("Full Width List") + } items(samples) { item -> ListRowItem( backgroundType = item.backgroundType, @@ -321,6 +330,9 @@ fun Lists() { color = MisticaTheme.colors.divider ) } + item { + SectionTitle("Boxed List") + } items(samples.map { it.copy(backgroundType = BackgroundType.TYPE_BOXED) }) { item -> @@ -338,6 +350,9 @@ fun Lists() { bottom = item.bottom, ) } + item { + SectionTitle("Boxed Inverse List") + } items(samples.map { it.copy( backgroundType = BackgroundType.TYPE_BOXED_INVERSE, @@ -358,6 +373,17 @@ fun Lists() { bottom = item.bottom, ) } + item { + SectionTitle("Clickable Asset") + ClickableAssetSample( + context = context, + onRowClick = {}, + ) + ClickableAssetSample( + context = context, + onRowClick = { Toast.makeText(context, "Row Clicked", Toast.LENGTH_SHORT).show() }, + ) + } } } @@ -389,6 +415,15 @@ fun Avatar(url: String) { ) } +@Composable +private fun SectionTitle(title: String) { + Text( + text = title.uppercase(), + style = MaterialTheme.typography.h6.copy(fontSize = 14.sp), + modifier = Modifier.padding(16.dp) + ) +} + @Composable private fun CustomSlot() { Box( @@ -412,3 +447,23 @@ private fun CustomSlot() { ) } } + +@Composable +@OptIn(ExperimentalMaterialApi::class) +private fun ClickableAssetSample(context: Context, onRowClick: () -> Unit) { + ListRowItem( + title = "Clickable Asset in Clickable Row", + subtitle = "Subtitle", + description = "Description", + isBadgeVisible = true, + badge = "1", + onClick = onRowClick, + listRowIcon = ListRowIcon.CircleIcon( + painterResource(id = R.drawable.ic_lists), + backgroundColor = MisticaTheme.colors.backgroundAlternative, + modifier = Modifier.clickable { + Toast.makeText(context, "Asset Clicked", Toast.LENGTH_SHORT).show() + } + ), + ) +} diff --git a/catalog/src/main/res/layout/screen_fragment_lists_catalog.xml b/catalog/src/main/res/layout/screen_fragment_lists_catalog.xml index 4f682345f..f43cf597e 100644 --- a/catalog/src/main/res/layout/screen_fragment_lists_catalog.xml +++ b/catalog/src/main/res/layout/screen_fragment_lists_catalog.xml @@ -71,5 +71,24 @@ app:listLayoutType="boxed" /> + + + + \ No newline at end of file diff --git a/library/src/main/java/com/telefonica/mistica/compose/list/ListRowIcon.kt b/library/src/main/java/com/telefonica/mistica/compose/list/ListRowIcon.kt index c63ecc8a4..c6d61ff77 100644 --- a/library/src/main/java/com/telefonica/mistica/compose/list/ListRowIcon.kt +++ b/library/src/main/java/com/telefonica/mistica/compose/list/ListRowIcon.kt @@ -28,17 +28,20 @@ sealed class ListRowIcon(val contentDescription: String?) { data class NormalIcon( val painter: Painter? = null, private val description: String? = null, + val modifier: Modifier = Modifier, ) : ListRowIcon(description) data class CircleIcon( val painter: Painter? = null, val backgroundColor: Color = Color.Transparent, private val description: String? = null, + val modifier: Modifier = Modifier, ) : ListRowIcon(description) data class SmallAsset( val painter: Painter? = null, private val description: String? = null, + val modifier: Modifier = Modifier, ) : ListRowIcon(description) data class LargeAsset( @@ -46,6 +49,7 @@ sealed class ListRowIcon(val contentDescription: String?) { val aspectRatio: AspectRatio = AspectRatio.RATIO_1_1, val contentScale: ContentScale = ContentScale.Crop, private val description: String? = null, + val modifier: Modifier = Modifier, ) : ListRowIcon(description) data class ImageAsset( @@ -53,6 +57,7 @@ sealed class ListRowIcon(val contentDescription: String?) { val dimensions: ImageDimensions? = null, val contentScale: ContentScale = ContentScale.Crop, private val description: String? = null, + val modifier: Modifier = Modifier, ) : ListRowIcon(description) enum class AspectRatio(val width: Dp, val height: Dp) { @@ -75,9 +80,9 @@ sealed class ListRowIcon(val contentDescription: String?) { @Composable private fun NormalIcon.DrawNormalIcon() { Box( - modifier = Modifier + modifier = modifier .size(40.dp) - .wrapContentSize(align = Alignment.Center) + .wrapContentSize(align = Alignment.Center), ) { painter?.let { Icon( @@ -94,6 +99,7 @@ sealed class ListRowIcon(val contentDescription: String?) { private fun CircleIcon.DrawCircleIcon() { Circle( color = backgroundColor, + modifier = modifier, ) { painter?.let { Icon( @@ -110,7 +116,7 @@ sealed class ListRowIcon(val contentDescription: String?) { Image( painter = painter, contentDescription = contentDescription, - modifier = Modifier + modifier = modifier .size(40.dp) .clip(CircleShape), contentScale = ContentScale.Crop, @@ -124,7 +130,7 @@ sealed class ListRowIcon(val contentDescription: String?) { Image( painter = painter, contentDescription = contentDescription, - modifier = Modifier + modifier = modifier .height(aspectRatio.height) .width(aspectRatio.width) .clip(RoundedCornerShape(4.dp)), @@ -139,7 +145,7 @@ sealed class ListRowIcon(val contentDescription: String?) { Image( painter = painter, contentDescription = contentDescription, - modifier = Modifier + modifier = modifier .width(dimensions?.width?.dp ?: dimensionResource(id = R.dimen.asset_default_size)) .height(dimensions?.height?.dp ?: dimensionResource(id = R.dimen.asset_default_size)) .clip(RoundedCornerShape(4.dp)), diff --git a/library/src/main/java/com/telefonica/mistica/compose/shape/Circle.kt b/library/src/main/java/com/telefonica/mistica/compose/shape/Circle.kt index 8c8774d93..36324ec99 100644 --- a/library/src/main/java/com/telefonica/mistica/compose/shape/Circle.kt +++ b/library/src/main/java/com/telefonica/mistica/compose/shape/Circle.kt @@ -16,12 +16,13 @@ import com.telefonica.mistica.compose.theme.MisticaTheme @Composable fun Circle( + modifier: Modifier = Modifier, color: Color = MisticaTheme.colors.neutralLow, size: Dp = 40.dp, content: @Composable (() -> Unit), ) { Box( - modifier = Modifier + modifier = modifier .size(size) .clip(CircleShape) .background(color) diff --git a/library/src/main/java/com/telefonica/mistica/list/ListRowView.kt b/library/src/main/java/com/telefonica/mistica/list/ListRowView.kt index a26d9bc71..ce5f5ef7d 100644 --- a/library/src/main/java/com/telefonica/mistica/list/ListRowView.kt +++ b/library/src/main/java/com/telefonica/mistica/list/ListRowView.kt @@ -309,6 +309,10 @@ class ListRowView @JvmOverloads constructor( } } + fun setAssetOnClickListener(clickListener: OnClickListener) { + assetImageLayout.setOnClickListener(clickListener) + } + private fun updateIconVisibility() { assetCircularImageView.isVisible = assetType == TYPE_IMAGE assetRoundedImageView.isVisible = assetType == TYPE_IMAGE_1_1 || assetType == TYPE_IMAGE_7_10 diff --git a/library/src/test/java/com/telefonica/mistica/compose/list/ListRowItemKtTest.kt b/library/src/test/java/com/telefonica/mistica/compose/list/ListRowItemKtTest.kt index a702b665a..69dfe17e0 100644 --- a/library/src/test/java/com/telefonica/mistica/compose/list/ListRowItemKtTest.kt +++ b/library/src/test/java/com/telefonica/mistica/compose/list/ListRowItemKtTest.kt @@ -1,9 +1,14 @@ package com.telefonica.mistica.compose.list +import androidx.compose.foundation.clickable import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource +import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performClick import com.telefonica.mistica.compose.shape.Chevron import com.telefonica.mistica.compose.tag.Tag import com.telefonica.mistica.compose.theme.MisticaTheme @@ -15,6 +20,9 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import com.telefonica.mistica.R +import org.junit.Assert.assertEquals + +private const val LIST_ROW_ITEM_ASSET_TAG = "listRowItemAssetTag" @RunWith(RobolectricTestRunner::class) internal class ListRowItemKtTest: ScreenshotsTest() { @@ -35,14 +43,30 @@ internal class ListRowItemKtTest: ScreenshotsTest() { `then screenshot is OK`() } + @Test + fun `check ListRowItem with clickable asset`() { + var clicked = 0 + val onAssetClick: () -> Unit = { + clicked++ + } + `when ListRowItem with asset`( + dimensions = ImageDimensions(width = 44, height = 44), + onAssetClick = onAssetClick, + ) + composeTestRule.onNode(hasTestTag(LIST_ROW_ITEM_ASSET_TAG)).performClick() + + assertEquals(1, clicked) + } + @OptIn(ExperimentalMaterialApi::class) - private fun `when ListRowItem with asset`(dimensions: ImageDimensions) { + private fun `when ListRowItem with asset`(dimensions: ImageDimensions, onAssetClick: () -> Unit = {}) { composeTestRule.setContent { MisticaTheme(brand = MovistarBrand) { ListRowItem( listRowIcon = ListRowIcon.ImageAsset( painter = painterResource(id = R.drawable.placeholder), dimensions = ImageDimensions(width = dimensions.width, height = dimensions.height), + modifier = Modifier.testTag(LIST_ROW_ITEM_ASSET_TAG).clickable { onAssetClick() }, ), headline = Tag("Promo"), isBadgeVisible = true, diff --git a/library/src/test/java/com/telefonica/mistica/list/ListRowViewTest.kt b/library/src/test/java/com/telefonica/mistica/list/ListRowViewTest.kt index 144d9e6d1..4142e7bfb 100644 --- a/library/src/test/java/com/telefonica/mistica/list/ListRowViewTest.kt +++ b/library/src/test/java/com/telefonica/mistica/list/ListRowViewTest.kt @@ -7,6 +7,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule import com.telefonica.mistica.DummyActivity import com.telefonica.mistica.R import com.telefonica.mistica.testutils.ScreenshotsTest +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -26,4 +27,20 @@ internal class ListRowViewTest: ScreenshotsTest() { compareScreenshot(Espresso.onView(ViewMatchers.withId(R.id.dummy_activity_wrapper))) } } + + @Test + fun `check ListRowView xml onClick`() { + rule.scenario.onActivity { activity -> + var clicks = 0 + val wrapper: FrameLayout = activity.findViewById(R.id.dummy_activity_wrapper) + activity.layoutInflater.inflate(R.layout.test_list_row_view, wrapper, true) + + with (activity.findViewById(R.id.list_row_view_32)) { + setOnClickListener { clicks++ } + performClick() + } + + assertEquals(1, clicks) + } + } } \ No newline at end of file diff --git a/library/src/test/res/layout/test_list_row_view.xml b/library/src/test/res/layout/test_list_row_view.xml index 9b1dfea6f..4a596a563 100644 --- a/library/src/test/res/layout/test_list_row_view.xml +++ b/library/src/test/res/layout/test_list_row_view.xml @@ -7,6 +7,7 @@ android:orientation="vertical">