Skip to content

Commit 54f6505

Browse files
[SDK-386] embedded card improvements (#1009)
1 parent 5e44cba commit 54f6505

6 files changed

Lines changed: 64 additions & 30 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## [Unreleased]
66
### Fixed
7+
- 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, 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.
78
- Fixed `ConcurrentModificationException` crash during device token registration caused by concurrent access to `deviceAttributes`.
89
- Fixed possible `NoSuchMethodException` crash on Android 5-10 caused by using `Map.of()` which is unavailable on those versions
910

11+
### Added
12+
- Added `imageScaleType` to `IterableEmbeddedViewConfig` to allow configuring how the image is scaled within the 16:9 container for embedded message views.
13+
- Added default values to all `IterableEmbeddedViewConfig` constructor parameters for easier configuration.
14+
1015
### Removed
1116
- Removed insecure `AES/CBC/PKCS5Padding` encryption from `IterableDataEncryptor`. The SDK now exclusively uses `AES/GCM/NoPadding`. The legacy CBC algorithm was only used on Android versions below KitKat (API 19), which have been unsupported since `minSdkVersion` was raised to 21.
1217

iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,17 @@ class IterableEmbeddedView() : Fragment() {
104104
val view = when (viewType) {
105105
IterableEmbeddedViewType.BANNER -> {
106106
val bannerView = inflater.inflate(R.layout.banner_view, container, false)
107-
bind(viewType, bannerView, message)
107+
bind(viewType, bannerView, message, config)
108108
bannerView
109109
}
110110
IterableEmbeddedViewType.CARD -> {
111111
val cardView = inflater.inflate(R.layout.card_view, container, false)
112-
bind(viewType, cardView, message)
112+
bind(viewType, cardView, message, config)
113113
cardView
114114
}
115115
IterableEmbeddedViewType.NOTIFICATION -> {
116116
val notificationView = inflater.inflate(R.layout.notification_view, container, false)
117-
bind(viewType, notificationView, message)
117+
bind(viewType, notificationView, message, config)
118118
notificationView
119119
}
120120
}
@@ -167,7 +167,7 @@ class IterableEmbeddedView() : Fragment() {
167167
bodyText.setTextColor(bodyTextColor)
168168
}
169169

170-
private fun bind(viewType: IterableEmbeddedViewType, view: View, message: IterableEmbeddedMessage): View {
170+
private fun bind(viewType: IterableEmbeddedViewType, view: View, message: IterableEmbeddedMessage, config: IterableEmbeddedViewConfig?): View {
171171
val embeddedMessageViewTitle: TextView = view.findViewById(R.id.embedded_message_title)
172172
val embeddedMessageViewBody: TextView = view.findViewById(R.id.embedded_message_body)
173173
val embeddedMessageViewButton: Button = view.findViewById(R.id.embedded_message_first_button)
@@ -179,6 +179,7 @@ class IterableEmbeddedView() : Fragment() {
179179
if(message.elements?.mediaURL?.isEmpty() == true) {
180180
embeddedMessageImageView.visibility = View.GONE
181181
} else {
182+
config?.let { embeddedMessageImageView.scaleType = it.imageScaleType }
182183
Glide.with(view.context).load(message.elements?.mediaURL).into(embeddedMessageImageView)
183184
embeddedMessageImageView.contentDescription = message.elements?.mediaUrlCaption
184185
}

iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedViewArguments.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.iterable.iterableapi.ui.embedded
22

33
import android.os.Bundle
4+
import android.widget.ImageView
45
import com.iterable.iterableapi.IterableEmbeddedMessage
56
import com.iterable.iterableapi.IterableLogger
67
import org.json.JSONException
@@ -23,6 +24,7 @@ internal object IterableEmbeddedViewArguments {
2324
private const val KEY_SECONDARY_BTN_TEXT = "secondary_btn_text"
2425
private const val KEY_TITLE_COLOR = "title_color"
2526
private const val KEY_BODY_COLOR = "body_color"
27+
private const val KEY_IMAGE_SCALE_TYPE = "image_scale_type"
2628

2729
fun toBundle(
2830
viewType: IterableEmbeddedViewType,
@@ -78,7 +80,8 @@ internal object IterableEmbeddedViewArguments {
7880
arguments.containsKey(KEY_SECONDARY_BTN_BG) ||
7981
arguments.containsKey(KEY_SECONDARY_BTN_TEXT) ||
8082
arguments.containsKey(KEY_TITLE_COLOR) ||
81-
arguments.containsKey(KEY_BODY_COLOR)
83+
arguments.containsKey(KEY_BODY_COLOR) ||
84+
arguments.containsKey(KEY_IMAGE_SCALE_TYPE)
8285

8386
return if (hasConfig) {
8487
IterableEmbeddedViewConfig(
@@ -91,7 +94,13 @@ internal object IterableEmbeddedViewArguments {
9194
secondaryBtnBackgroundColor = arguments.getIntOrNull(KEY_SECONDARY_BTN_BG),
9295
secondaryBtnTextColor = arguments.getIntOrNull(KEY_SECONDARY_BTN_TEXT),
9396
titleTextColor = arguments.getIntOrNull(KEY_TITLE_COLOR),
94-
bodyTextColor = arguments.getIntOrNull(KEY_BODY_COLOR)
97+
bodyTextColor = arguments.getIntOrNull(KEY_BODY_COLOR),
98+
imageScaleType = try {
99+
arguments.getString(KEY_IMAGE_SCALE_TYPE)?.let { ImageView.ScaleType.valueOf(it) }
100+
?: IterableEmbeddedViewConfig.DEFAULT_IMAGE_SCALE_TYPE
101+
} catch (e: IllegalArgumentException) {
102+
IterableEmbeddedViewConfig.DEFAULT_IMAGE_SCALE_TYPE
103+
}
95104
)
96105
} else {
97106
null
@@ -110,6 +119,7 @@ internal object IterableEmbeddedViewArguments {
110119
cfg.secondaryBtnTextColor?.let { putInt(KEY_SECONDARY_BTN_TEXT, it) }
111120
cfg.titleTextColor?.let { putInt(KEY_TITLE_COLOR, it) }
112121
cfg.bodyTextColor?.let { putInt(KEY_BODY_COLOR, it) }
122+
putString(KEY_IMAGE_SCALE_TYPE, cfg.imageScaleType.name)
113123
}
114124
}
115125

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
package com.iterable.iterableapi.ui.embedded
22

3-
data class IterableEmbeddedViewConfig(
4-
val backgroundColor: Int?,
5-
val borderColor: Int?,
6-
val borderWidth: Int?,
7-
val borderCornerRadius: Float?,
8-
val primaryBtnBackgroundColor: Int?,
9-
val primaryBtnTextColor: Int?,
10-
val secondaryBtnBackgroundColor: Int?,
11-
val secondaryBtnTextColor: Int?,
12-
val titleTextColor: Int?,
13-
val bodyTextColor: Int?
14-
)
3+
import android.widget.ImageView
4+
5+
data class IterableEmbeddedViewConfig @JvmOverloads constructor(
6+
val backgroundColor: Int? = null,
7+
val borderColor: Int? = null,
8+
val borderWidth: Int? = null,
9+
val borderCornerRadius: Float? = null,
10+
val primaryBtnBackgroundColor: Int? = null,
11+
val primaryBtnTextColor: Int? = null,
12+
val secondaryBtnBackgroundColor: Int? = null,
13+
val secondaryBtnTextColor: Int? = null,
14+
val titleTextColor: Int? = null,
15+
val bodyTextColor: Int? = null,
16+
/** Image scale type applied to CARD and BANNER views. */
17+
val imageScaleType: ImageView.ScaleType = DEFAULT_IMAGE_SCALE_TYPE
18+
) {
19+
companion object {
20+
@JvmField
21+
val DEFAULT_IMAGE_SCALE_TYPE: ImageView.ScaleType = ImageView.ScaleType.CENTER_CROP
22+
}
23+
}

iterableapi-ui/src/main/res/layout-v21/card_view.xml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,38 @@
33
xmlns:android="http://schemas.android.com/apk/res/android"
44
xmlns:app="http://schemas.android.com/apk/res-auto"
55
android:layout_width="match_parent"
6-
android:layout_height="match_parent"
6+
android:layout_height="wrap_content"
77
android:layout_gravity="center_vertical"
8+
android:layout_marginStart="16dp"
89
android:layout_marginTop="8dp"
10+
android:layout_marginEnd="16dp"
911
android:layout_marginLeft="16dp"
12+
android:layout_marginRight="16dp"
1013
android:layout_marginBottom="12dp"
1114
app:cardCornerRadius="8dp"
1215
app:cardElevation="0dp"
1316
android:background="@drawable/banner_card_border"
17+
android:clipToOutline="true"
18+
android:outlineProvider="background"
1419
android:orientation="vertical">
1520

1621
<com.google.android.material.imageview.ShapeableImageView
1722
android:id="@+id/embedded_message_image"
1823
android:layout_width="0dp"
1924
android:layout_height="0dp"
2025
android:contentDescription=""
21-
android:scaleType="centerCrop"
26+
app:layout_constraintDimensionRatio="H,16:9"
2227
app:layout_constraintEnd_toEndOf="parent"
2328
app:layout_constraintStart_toStartOf="parent"
2429
app:layout_constraintTop_toTopOf="parent"
25-
app:layout_constraintBottom_toTopOf="@id/embedded_message_text_container"
26-
app:shapeAppearanceOverlay="@style/classCardStyle" />
30+
/> <!-- 16:9 aspect ratio. Scale type is configured via IterableEmbeddedViewConfig.imageScaleType -->
2731

2832
<LinearLayout
2933
android:id="@+id/embedded_message_text_container"
3034
android:layout_width="0dp"
31-
android:layout_height="@dimen/card_text_container_height"
35+
android:layout_height="wrap_content"
3236
android:orientation="vertical"
33-
app:layout_constraintBottom_toTopOf="@id/embedded_message_buttons_container"
37+
app:layout_constraintTop_toBottomOf="@id/embedded_message_image"
3438
app:layout_constraintStart_toStartOf="parent"
3539
app:layout_constraintEnd_toEndOf="parent">
3640

@@ -79,6 +83,7 @@
7983
android:orientation="horizontal"
8084
app:layout_constraintEnd_toEndOf="parent"
8185
app:layout_constraintStart_toStartOf="parent"
86+
app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container"
8287
app:layout_constraintBottom_toBottomOf="parent">
8388

8489
<com.google.android.material.button.MaterialButton

iterableapi-ui/src/main/res/layout/card_view.xml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,39 @@
22
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
android:layout_width="match_parent"
5-
android:layout_height="match_parent"
5+
android:layout_height="wrap_content"
66
xmlns:tools="http://schemas.android.com/tools"
77
android:layout_gravity="center_vertical"
88
android:layout_marginStart="16dp"
99
android:layout_marginTop="8dp"
10+
android:layout_marginEnd="16dp"
1011
android:layout_marginLeft="16dp"
12+
android:layout_marginRight="16dp"
1113
android:layout_marginBottom="12dp"
1214
app:cardCornerRadius="8dp"
1315
app:cardElevation="0dp"
1416
android:background="@drawable/banner_card_border"
17+
android:clipToOutline="true"
18+
android:outlineProvider="background"
1519
android:orientation="vertical">
1620

1721
<com.google.android.material.imageview.ShapeableImageView
1822
android:id="@+id/embedded_message_image"
1923
android:layout_width="0dp"
2024
android:layout_height="0dp"
2125
android:contentDescription=""
22-
android:scaleType="centerCrop"
26+
app:layout_constraintDimensionRatio="H,16:9"
2327
app:layout_constraintEnd_toEndOf="parent"
2428
app:layout_constraintStart_toStartOf="parent"
2529
app:layout_constraintTop_toTopOf="parent"
26-
app:layout_constraintBottom_toTopOf="@id/embedded_message_text_container"
27-
app:shapeAppearanceOverlay="@style/classCardStyle" />
30+
/> <!-- 16:9 aspect ratio. Scale type is configured via IterableEmbeddedViewConfig.imageScaleType -->
2831

2932
<LinearLayout
3033
android:id="@+id/embedded_message_text_container"
3134
android:layout_width="0dp"
32-
android:layout_height="@dimen/card_text_container_height"
35+
android:layout_height="wrap_content"
3336
android:orientation="vertical"
34-
app:layout_constraintBottom_toTopOf="@id/embedded_message_buttons_container"
37+
app:layout_constraintTop_toBottomOf="@id/embedded_message_image"
3538
app:layout_constraintStart_toStartOf="parent"
3639
app:layout_constraintEnd_toEndOf="parent">
3740

@@ -79,6 +82,7 @@
7982
android:orientation="horizontal"
8083
app:layout_constraintEnd_toEndOf="parent"
8184
app:layout_constraintStart_toStartOf="parent"
85+
app:layout_constraintTop_toBottomOf="@id/embedded_message_text_container"
8286
app:layout_constraintBottom_toBottomOf="parent">
8387

8488
<com.google.android.material.button.MaterialButton

0 commit comments

Comments
 (0)