diff --git a/.gitignore b/.gitignore index 35414c564..6d832f70d 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,6 @@ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup pom.xml.next -release.properties \ No newline at end of file +release.properties + +jacoco.exec \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b205c63..5abfec8e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] + #### Added - nothing yet @@ -12,6 +13,17 @@ This project adheres to [Semantic Versioning](http://semver.org/). #### Changed - nothing yet +## [3.5.0] +#### Added +- introduces support for embedded messaging: an eligibility–based, personalized messages sent from Iterable to your mobile and web apps, which can display them inline, using native interface components. +- To display embedded messages, you can use customizable, out-of-the-box components provided by the SDK (cards, notifications, banners), or you can build fully custom components of your own design. +- To learn more, read [Embedded Messages with Iterable's iOS SDK](https://support.iterable.com/hc/articles/23061840746900). + +#### Changed +- `IterableConfig` is updated with an `enableEmbeddedMessaging` flag that needs to be set to true to allow use of embedded messaging functionality + +## [3.5.0-beta1](https://github.com/Iterable/iterable-android-sdk/releases/tag/3.5.0-beta1) + ## [3.4.17](https://github.com/Iterable/iterable-android-sdk/releases/tag/3.4.17) #### Added - when JWT is invalid, `IterableAuthManager` is updated to fetch and store a new JWT token locally diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3b8d068d2..518e50cb1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Tue Apr 28 13:23:09 PDT 2020 +#Tue Oct 10 10:01:47 MDT 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/iterableapi-ui/build.gradle b/iterableapi-ui/build.gradle index be5fb9da7..74cb4284e 100644 --- a/iterableapi-ui/build.gradle +++ b/iterableapi-ui/build.gradle @@ -7,7 +7,7 @@ android { namespace 'com.iterable.iterableapi.ui' defaultConfig { - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 28 vectorDrawables.useSupportLibrary = true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -37,17 +37,21 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.google.android.flexbox:flexbox:3.0.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation "com.github.bumptech.glide:glide:4.8.0" + implementation 'com.google.android.material:material:1.2.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' - } ext { libraryName = 'iterableapi-ui' - libraryVersion = '3.4.17' + libraryVersion = '3.5.0-beta1' } if (hasProperty("mavenPublishEnabled")) { @@ -57,6 +61,8 @@ if (hasProperty("mavenPublishEnabled")) { task javadoc(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + + exclude '**/*.kt' } // A hack to import the classpath and BuildConfig into the javadoc task 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 new file mode 100644 index 000000000..cec97ed48 --- /dev/null +++ b/iterableapi-ui/src/main/java/com/iterable/iterableapi/ui/embedded/IterableEmbeddedView.kt @@ -0,0 +1,191 @@ +package com.iterable.iterableapi.ui.embedded + +import android.graphics.drawable.GradientDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.bumptech.glide.Glide +import com.google.android.flexbox.FlexboxLayout +import com.iterable.iterableapi.EmbeddedMessageElementsButton +import com.iterable.iterableapi.IterableApi +import com.iterable.iterableapi.IterableEmbeddedMessage +import com.iterable.iterableapi.ui.R + +class IterableEmbeddedView( + private var viewType: IterableEmbeddedViewType, + private var message: IterableEmbeddedMessage, + private var config: IterableEmbeddedViewConfig? +): Fragment() { + + private val defaultBackgroundColor : Int by lazy { getDefaultColor(viewType, R.color.notification_background_color, R.color.banner_background_color, R.color.banner_background_color) } + private val defaultBorderColor : Int by lazy { getDefaultColor(viewType, R.color.notification_border_color, R.color.banner_border_color, R.color.banner_border_color) } + private val defaultPrimaryBtnBackgroundColor: Int by lazy { getDefaultColor(viewType, R.color.white, R.color.white, R.color.banner_button_color) } + private val defaultPrimaryBtnTextColor: Int by lazy { getDefaultColor(viewType, R.color.notification_text_color, R.color.banner_button_color, R.color.white) } + private val defaultSecondaryBtnBackgroundColor: Int by lazy { getDefaultColor(viewType, R.color.notification_background_color, R.color.white, R.color.white) } + private val defaultSecondaryBtnTextColor: Int by lazy { getDefaultColor(viewType, R.color.notification_text_color, R.color.banner_button_color, R.color.banner_button_color) } + private val defaultTitleTextColor: Int by lazy { getDefaultColor(viewType, R.color.notification_text_color, R.color.title_text_color, R.color.title_text_color) } + private val defaultBodyTextColor: Int by lazy { getDefaultColor(viewType, R.color.notification_text_color, R.color.body_text_color, R.color.body_text_color) } + private val defaultBorderWidth = 1 + private val defaultBorderCornerRadius = 8f + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val view = when (viewType) { + IterableEmbeddedViewType.BANNER -> { + val bannerView = inflater.inflate(R.layout.banner_view, container, false) + bind(viewType, bannerView, message) + bannerView + } + IterableEmbeddedViewType.CARD -> { + val cardView = inflater.inflate(R.layout.card_view, container, false) + bind(viewType, cardView, message) + cardView + } + IterableEmbeddedViewType.NOTIFICATION -> { + val notificationView = inflater.inflate(R.layout.notification_view, container, false) + bind(viewType, notificationView, message) + notificationView + } + } + + setDefaultAction(view, message) + configure(view, viewType, config) + + return view + } + + private fun configure(view: View, viewType: IterableEmbeddedViewType, config: IterableEmbeddedViewConfig?) { + + val backgroundColor = config?.backgroundColor.takeIf { it != null } ?: defaultBackgroundColor + val borderColor = config?.borderColor.takeIf { it != null } ?: defaultBorderColor + val borderWidth = config?.borderWidth.takeIf { it != null } ?: defaultBorderWidth + val borderCornerRadius = config?.borderCornerRadius.takeIf { it != null } ?: defaultBorderCornerRadius + + val primaryBtnBackgroundColor = config?.primaryBtnBackgroundColor.takeIf { it != null } ?: defaultPrimaryBtnBackgroundColor + val primaryBtnTextColor = config?.primaryBtnTextColor.takeIf { it != null } ?: defaultPrimaryBtnTextColor + + val secondaryBtnBackgroundColor = config?.secondaryBtnBackgroundColor.takeIf { it != null } ?: defaultSecondaryBtnBackgroundColor + val secondaryBtnTextColor = config?.secondaryBtnTextColor.takeIf { it != null } ?: defaultSecondaryBtnTextColor + + val titleTextColor = config?.titleTextColor.takeIf { it != null } ?: defaultTitleTextColor + val bodyTextColor = config?.bodyTextColor.takeIf { it != null } ?: defaultBodyTextColor + + val gradientDrawable = GradientDrawable() + + gradientDrawable.setColor(backgroundColor) + gradientDrawable.setStroke(borderWidth, borderColor) + gradientDrawable.cornerRadius = borderCornerRadius + view.setBackgroundDrawable(gradientDrawable) + + val firstButton = view.findViewById