From 33c7253b8bfd76dddc90c62240882b554b007300 Mon Sep 17 00:00:00 2001 From: Franco Zalamena Date: Tue, 31 Mar 2026 17:04:05 +0100 Subject: [PATCH 1/4] Embedded Card Layout fixes --- .../ui/embedded/IterableEmbeddedView.kt | 9 ++-- .../embedded/IterableEmbeddedViewArguments.kt | 20 ++++++++- .../ui/embedded/IterableEmbeddedViewConfig.kt | 5 ++- .../src/main/res/layout-v21/card_view.xml | 41 ++++++++----------- .../src/main/res/layout/card_view.xml | 40 ++++++++---------- 5 files changed, 60 insertions(+), 55 deletions(-) diff --git a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt index 1d9c22553..8ab42c518 100644 --- a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt @@ -104,17 +104,17 @@ class IterableEmbeddedView() : Fragment() { val view = when (viewType) { IterableEmbeddedViewType.BANNER -> { val bannerView = inflater.inflate(R.layout.banner_view, container, false) - bind(viewType, bannerView, message) + bind(viewType, bannerView, message, config) bannerView } IterableEmbeddedViewType.CARD -> { val cardView = inflater.inflate(R.layout.card_view, container, false) - bind(viewType, cardView, message) + bind(viewType, cardView, message, config) cardView } IterableEmbeddedViewType.NOTIFICATION -> { val notificationView = inflater.inflate(R.layout.notification_view, container, false) - bind(viewType, notificationView, message) + bind(viewType, notificationView, message, config) notificationView } } @@ -167,7 +167,7 @@ class IterableEmbeddedView() : Fragment() { bodyText.setTextColor(bodyTextColor) } - private fun bind(viewType: IterableEmbeddedViewType, view: View, message: IterableEmbeddedMessage): View { + private fun bind(viewType: IterableEmbeddedViewType, view: View, message: IterableEmbeddedMessage, config: IterableEmbeddedViewConfig?): View { val embeddedMessageViewTitle: TextView = view.findViewById(R.id.embedded_message_title) val embeddedMessageViewBody: TextView = view.findViewById(R.id.embedded_message_body) val embeddedMessageViewButton: Button = view.findViewById(R.id.embedded_message_first_button) @@ -179,6 +179,7 @@ class IterableEmbeddedView() : Fragment() { if(message.elements?.mediaURL?.isEmpty() == true) { embeddedMessageImageView.visibility = View.GONE } else { + config?.imageScaleType?.let { embeddedMessageImageView.scaleType = it } Glide.with(view.context).load(message.elements?.mediaURL).into(embeddedMessageImageView) embeddedMessageImageView.contentDescription = message.elements?.mediaUrlCaption } diff --git a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewArguments.kt b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewArguments.kt index a85850dd4..0bba74262 100644 --- a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewArguments.kt +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewArguments.kt @@ -1,6 +1,7 @@ package com.iterable.iterableapi.ui.embedded import android.os.Bundle +import android.widget.ImageView import com.iterable.iterableapi.IterableEmbeddedMessage import com.iterable.iterableapi.IterableLogger import org.json.JSONException @@ -23,6 +24,7 @@ internal object IterableEmbeddedViewArguments { private const val KEY_SECONDARY_BTN_TEXT = "secondary_btn_text" private const val KEY_TITLE_COLOR = "title_color" private const val KEY_BODY_COLOR = "body_color" + private const val KEY_IMAGE_SCALE_TYPE = "image_scale_type" fun toBundle( viewType: IterableEmbeddedViewType, @@ -78,7 +80,8 @@ internal object IterableEmbeddedViewArguments { arguments.containsKey(KEY_SECONDARY_BTN_BG) || arguments.containsKey(KEY_SECONDARY_BTN_TEXT) || arguments.containsKey(KEY_TITLE_COLOR) || - arguments.containsKey(KEY_BODY_COLOR) + arguments.containsKey(KEY_BODY_COLOR) || + arguments.containsKey(KEY_IMAGE_SCALE_TYPE) return if (hasConfig) { IterableEmbeddedViewConfig( @@ -91,7 +94,15 @@ internal object IterableEmbeddedViewArguments { secondaryBtnBackgroundColor = arguments.getIntOrNull(KEY_SECONDARY_BTN_BG), secondaryBtnTextColor = arguments.getIntOrNull(KEY_SECONDARY_BTN_TEXT), titleTextColor = arguments.getIntOrNull(KEY_TITLE_COLOR), - bodyTextColor = arguments.getIntOrNull(KEY_BODY_COLOR) + bodyTextColor = arguments.getIntOrNull(KEY_BODY_COLOR), + imageScaleType = arguments.getStringOrNull(KEY_IMAGE_SCALE_TYPE)?.let { + try { + ImageView.ScaleType.valueOf(it) + } catch (e: IllegalArgumentException) { + IterableLogger.e(TAG, "Invalid image scale type: $it, using default") + null + } + } ) } else { null @@ -110,6 +121,7 @@ internal object IterableEmbeddedViewArguments { cfg.secondaryBtnTextColor?.let { putInt(KEY_SECONDARY_BTN_TEXT, it) } cfg.titleTextColor?.let { putInt(KEY_TITLE_COLOR, it) } cfg.bodyTextColor?.let { putInt(KEY_BODY_COLOR, it) } + cfg.imageScaleType?.let { putString(KEY_IMAGE_SCALE_TYPE, it.name) } } } @@ -120,4 +132,8 @@ internal object IterableEmbeddedViewArguments { private fun Bundle.getFloatOrNull(key: String): Float? { return if (containsKey(key)) getFloat(key) else null } + + private fun Bundle.getStringOrNull(key: String): String? { + return if (containsKey(key)) getString(key) else null + } } diff --git a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt index 7b0b9f5f1..0450539e9 100644 --- a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt @@ -1,5 +1,7 @@ package com.iterable.iterableapi.ui.embedded +import android.widget.ImageView + data class IterableEmbeddedViewConfig( val backgroundColor: Int?, val borderColor: Int?, @@ -10,5 +12,6 @@ data class IterableEmbeddedViewConfig( val secondaryBtnBackgroundColor: Int?, val secondaryBtnTextColor: Int?, val titleTextColor: Int?, - val bodyTextColor: Int? + val bodyTextColor: Int?, + val imageScaleType: ImageView.ScaleType? = null ) \ No newline at end of file diff --git a/iterableapi-ui/src/main/res/layout-v21/card_view.xml b/iterableapi-ui/src/main/res/layout-v21/card_view.xml index d481ffe23..1df8ceb30 100644 --- a/iterableapi-ui/src/main/res/layout-v21/card_view.xml +++ b/iterableapi-ui/src/main/res/layout-v21/card_view.xml @@ -3,10 +3,13 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:layout_marginStart="16dp" android:layout_marginTop="8dp" + android:layout_marginEnd="16dp" android:layout_marginLeft="16dp" + android:layout_marginRight="16dp" android:layout_marginBottom="12dp" app:cardCornerRadius="8dp" app:cardElevation="0dp" @@ -19,18 +22,18 @@ android:layout_height="0dp" android:contentDescription="" android:scaleType="centerCrop" + app:layout_constraintDimensionRatio="H,16:9" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/embedded_message_text_container" app:shapeAppearanceOverlay="@style/classCardStyle" /> @@ -79,41 +82,31 @@ android:orientation="horizontal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toBottomOf="parent"> + app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container"> + android:textSize="14sp" /> + android:textSize="14sp" /> diff --git a/iterableapi-ui/src/main/res/layout/card_view.xml b/iterableapi-ui/src/main/res/layout/card_view.xml index db5d3957b..b2c7bcb5c 100644 --- a/iterableapi-ui/src/main/res/layout/card_view.xml +++ b/iterableapi-ui/src/main/res/layout/card_view.xml @@ -2,12 +2,14 @@ @@ -79,41 +81,31 @@ android:orientation="horizontal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toBottomOf="parent"> + app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container"> + android:textSize="14sp" /> + android:textSize="14sp" /> From 676d0964a07515c1bf0b5ecf189ff42d71077e16 Mon Sep 17 00:00:00 2001 From: Franco Zalamena Date: Tue, 31 Mar 2026 17:13:54 +0100 Subject: [PATCH 2/4] Default params for embedded config --- .../ui/embedded/IterableEmbeddedViewConfig.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt index 0450539e9..2dee3f023 100644 --- a/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewConfig.kt @@ -3,15 +3,15 @@ package com.iterable.iterableapi.ui.embedded import android.widget.ImageView data class IterableEmbeddedViewConfig( - val backgroundColor: Int?, - val borderColor: Int?, - val borderWidth: Int?, - val borderCornerRadius: Float?, - val primaryBtnBackgroundColor: Int?, - val primaryBtnTextColor: Int?, - val secondaryBtnBackgroundColor: Int?, - val secondaryBtnTextColor: Int?, - val titleTextColor: Int?, - val bodyTextColor: Int?, + val backgroundColor: Int? = null, + val borderColor: Int? = null, + val borderWidth: Int? = null, + val borderCornerRadius: Float? = null, + val primaryBtnBackgroundColor: Int? = null, + val primaryBtnTextColor: Int? = null, + val secondaryBtnBackgroundColor: Int? = null, + val secondaryBtnTextColor: Int? = null, + val titleTextColor: Int? = null, + val bodyTextColor: Int? = null, val imageScaleType: ImageView.ScaleType? = null ) \ No newline at end of file From c7229cbd5f1c4a9f6cb0ba94120cdc45461b3ee2 Mon Sep 17 00:00:00 2001 From: Franco Zalamena Date: Wed, 1 Apr 2026 17:29:44 +0100 Subject: [PATCH 3/4] Fixed embedded card appearance --- iterableapi-ui/src/main/res/layout-v21/card_view.xml | 7 +++++-- iterableapi-ui/src/main/res/layout/card_view.xml | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/iterableapi-ui/src/main/res/layout-v21/card_view.xml b/iterableapi-ui/src/main/res/layout-v21/card_view.xml index 1df8ceb30..e48487a17 100644 --- a/iterableapi-ui/src/main/res/layout-v21/card_view.xml +++ b/iterableapi-ui/src/main/res/layout-v21/card_view.xml @@ -14,6 +14,8 @@ app:cardCornerRadius="8dp" app:cardElevation="0dp" android:background="@drawable/banner_card_border" + android:clipToOutline="true" + android:outlineProvider="background" android:orientation="vertical"> + /> + app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container" + app:layout_constraintBottom_toBottomOf="parent"> + /> + app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container" + app:layout_constraintBottom_toBottomOf="parent"> Date: Wed, 1 Apr 2026 17:31:17 +0100 Subject: [PATCH 4/4] Changelog updates --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1432536b5..55f2649cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed +- Fixed `IterableEmbeddedView` card layout rendering issues: image now displays at a 16:9 aspect ratio instead of collapsing to zero height, card container no longer expands to fill the parent, buttons use a text style for better alignment with the campaign preview, missing end margin on the card is now applied, bottom spacing on buttons is no longer cut off, and the image properly clips to the card's rounded corners. + +### Added +- Added `imageScaleType` to `IterableEmbeddedViewConfig` to allow configuring the image scale type for embedded message views. +- Added default values to all `IterableEmbeddedViewConfig` constructor parameters for easier configuration. ## [3.7.0] - Replaced the deprecated `AsyncTask`-based push notification handling with `WorkManager` for improved reliability and compatibility with modern Android versions. No action is required.