diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index ed4d8207..f3883028 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -80,7 +80,7 @@ jobs:
SIGNING_KEY_FILE_AS_BASE64_STRING: ${{ secrets.SIGNING_KEY_FILE_AS_BASE64_STRING }}
release:
- needs: [publish-rees, version]
+ needs: [ publish-rees, version ]
uses: rees46/workflow/.github/workflows/reusable-android-release.yaml@master
permissions: write-all
with:
diff --git a/README.md b/README.md
index ce35fcb9..e938f1db 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,8 @@ This SDK can be used to integrate in your own app for Android in few steps.
## Documentation
-For detailed information on methods, please refer to the documentation available at the following link:
+For detailed information on methods, please refer to the documentation available at the following
+link:
[Official API references](https://reference.api.rees46.com/?kotlin#introduction)
diff --git a/build.gradle b/build.gradle
index 3f735138..9f5e1e6f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,31 +1,31 @@
buildscript {
- ext.kotlin_version = '2.0.0'
- repositories {
- google()
- mavenCentral()
- mavenLocal()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:8.5.2'
- classpath "com.google.gms:google-services:4.4.1"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- }
+ ext.kotlin_version = '2.0.0'
+ repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.5.2'
+ classpath "com.google.gms:google-services:4.4.1"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
}
plugins {
- id 'ru.vyarus.pom' version '2.2.2'
- id 'io.github.gradle-nexus.publish-plugin' version '1.1.0'
- id 'org.jetbrains.kotlin.android' version '2.0.0' apply false
+ id 'ru.vyarus.pom' version '2.2.2'
+ id 'io.github.gradle-nexus.publish-plugin' version '1.1.0'
+ id 'org.jetbrains.kotlin.android' version '2.0.0' apply false
}
allprojects {
- repositories {
- google()
- mavenCentral()
- mavenLocal()
- }
+ repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
+ }
}
tasks.register('clean', Delete) {
- delete rootProject.buildDir
+ delete rootProject.buildDir
}
diff --git a/gradle.properties b/gradle.properties
index faf8e131..8f549833 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,7 +15,6 @@ android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
-
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
diff --git a/personalization-sdk/build.gradle b/personalization-sdk/build.gradle
index ac086abd..89334a06 100644
--- a/personalization-sdk/build.gradle
+++ b/personalization-sdk/build.gradle
@@ -1,102 +1,102 @@
plugins {
- id 'com.android.library'
- id 'org.jetbrains.kotlin.android'
- id 'maven-publish'
- id 'signing'
- id 'kotlin-kapt'
+ id 'com.android.library'
+ id 'org.jetbrains.kotlin.android'
+ id 'maven-publish'
+ id 'signing'
+ id 'kotlin-kapt'
}
-version='2.0.36'
+version = '2.0.36'
android {
- compileSdkVersion 34
- flavorDimensions += 'default'
- viewBinding {
- enabled = true
- }
- dataBinding {
- enabled = true
- }
- defaultConfig {
- minSdkVersion 19
- targetSdkVersion 34
- buildConfigField "String", "VERSION_NAME", "\"" + version + "\""
- multiDexEnabled true
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_20
- targetCompatibility JavaVersion.VERSION_20
- }
-
- kotlinOptions {
- jvmTarget = '20'
- }
-
- sourceSets {
- main {
- main.java.srcDirs = ['src/main/kotlin']
- }
- }
-
- productFlavors {
- rees46 {
- dimension 'default'
- ext.set("group", "com.rees46")
- ext.set("libraryName", "com.rees46.sdk")
- ext.set("webSite", "https://rees46.com")
- ext.set("vcsUrl", "https://github.com/rees46/android-sdk")
- }
- personaclick {
- dimension 'default'
- ext.set("group", "com.personaclick")
- ext.set("libraryName", "com.personaclick.sdk")
- ext.set("webSite", "https://personaclick.com")
- ext.set("vcsUrl", "https://github.com/PersonaClick/android-sdk")
- }
- }
-
- testFixtures {
- enable = false
- }
-
- namespace 'com.personalization'
+ compileSdkVersion 34
+ flavorDimensions += 'default'
+ viewBinding {
+ enabled = true
+ }
+ dataBinding {
+ enabled = true
+ }
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion 34
+ buildConfigField "String", "VERSION_NAME", "\"" + version + "\""
+ multiDexEnabled true
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_20
+ targetCompatibility JavaVersion.VERSION_20
+ }
+
+ kotlinOptions {
+ jvmTarget = '20'
+ }
+
+ sourceSets {
+ main {
+ main.java.srcDirs = ['src/main/kotlin']
+ }
+ }
+
+ productFlavors {
+ rees46 {
+ dimension 'default'
+ ext.set("group", "com.rees46")
+ ext.set("libraryName", "com.rees46.sdk")
+ ext.set("webSite", "https://rees46.com")
+ ext.set("vcsUrl", "https://github.com/rees46/android-sdk")
+ }
+ personaclick {
+ dimension 'default'
+ ext.set("group", "com.personaclick")
+ ext.set("libraryName", "com.personaclick.sdk")
+ ext.set("webSite", "https://personaclick.com")
+ ext.set("vcsUrl", "https://github.com/PersonaClick/android-sdk")
+ }
+ }
+
+ testFixtures {
+ enable = false
+ }
+
+ namespace 'com.personalization'
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- implementation 'androidx.multidex:multidex:2.0.1'
- implementation 'androidx.recyclerview:recyclerview:1.3.2'
- implementation 'com.google.android.material:material:1.12.0'
- implementation 'org.jetbrains:annotations:24.1.0'
- implementation 'androidx.core:core-ktx:1.13.1'
- implementation 'androidx.work:work-runtime-ktx:2.9.1'
- implementation 'com.google.code.gson:gson:2.11.0'
- implementation 'org.jetbrains.kotlin:kotlin-stdlib'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
-
- implementation platform('com.google.firebase:firebase-bom:32.7.0')
- implementation 'com.google.firebase:firebase-messaging:23.4.1'
- implementation 'com.github.bumptech.glide:glide:4.16.0'
- implementation 'androidx.media3:media3-exoplayer:1.4.1'
- implementation 'androidx.media3:media3-ui:1.4.1'
- implementation 'com.google.dagger:dagger:2.51.1'
- kapt 'com.google.dagger:dagger-compiler:2.48'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'androidx.multidex:multidex:2.0.1'
+ implementation 'androidx.recyclerview:recyclerview:1.3.2'
+ implementation 'com.google.android.material:material:1.12.0'
+ implementation 'org.jetbrains:annotations:24.1.0'
+ implementation 'androidx.core:core-ktx:1.13.1'
+ implementation 'androidx.work:work-runtime-ktx:2.9.1'
+ implementation 'com.google.code.gson:gson:2.11.0'
+ implementation 'org.jetbrains.kotlin:kotlin-stdlib'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
+
+ implementation platform('com.google.firebase:firebase-bom:32.7.0')
+ implementation 'com.google.firebase:firebase-messaging:23.4.1'
+ implementation 'com.github.bumptech.glide:glide:4.16.0'
+ implementation 'androidx.media3:media3-exoplayer:1.4.1'
+ implementation 'androidx.media3:media3-ui:1.4.1'
+ implementation 'com.google.dagger:dagger:2.51.1'
+ kapt 'com.google.dagger:dagger-compiler:2.48'
}
configurations {
- rees46Debug
- rees46Release
- personaclickDebug
- personaclickRelease
+ rees46Debug
+ rees46Release
+ personaclickDebug
+ personaclickRelease
}
group = 'com.personalization'
@@ -104,57 +104,57 @@ group = 'com.personalization'
apply from: '../publish.gradle'
tasks.register('sourcesJar', Jar) {
- archiveClassifier.set('sources')
- from android.sourceSets.main.java.srcDirs
+ archiveClassifier.set('sources')
+ from android.sourceSets.main.java.srcDirs
}
tasks.register('javadoc', Javadoc) {
- source = fileTree(dir: 'src/main/kotlin', include: '**/*.kt')
- classpath += files("${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
- failOnError false
- options.encoding = 'UTF-8'
- options.charSet('UTF-8')
- options.links("http://docs.oracle.com/javase/7/docs/api/")
- options.links("http://d.android.com/reference/")
- destinationDir = file("${buildDir}/docs/javadoc")
+ source = fileTree(dir: 'src/main/kotlin', include: '**/*.kt')
+ classpath += files("${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+ failOnError false
+ options.encoding = 'UTF-8'
+ options.charSet('UTF-8')
+ options.links("http://docs.oracle.com/javase/7/docs/api/")
+ options.links("http://d.android.com/reference/")
+ destinationDir = file("${buildDir}/docs/javadoc")
}
tasks.register('javadocJar', Jar) {
- dependsOn javadoc
- archiveClassifier.set('javadoc')
- from javadoc.destinationDir
+ dependsOn javadoc
+ archiveClassifier.set('javadoc')
+ from javadoc.destinationDir
}
tasks.register('printVersionName') {
- doLast {
- println version
- }
+ doLast {
+ println version
+ }
}
tasks.register('increaseVersionCode') {
- doLast {
- def (major, minor, patch) = version.tokenize('.')
- major = major.toInteger()
- minor = minor.toInteger()
- patch = patch.toInteger()
+ doLast {
+ def (major, minor, patch) = version.tokenize('.')
+ major = major.toInteger()
+ minor = minor.toInteger()
+ patch = patch.toInteger()
- Integer newPatch = patch + 1
+ Integer newPatch = patch + 1
- String result = "$major.$minor.$newPatch"
+ String result = "$major.$minor.$newPatch"
- String s = buildFile.getText().replaceFirst("version='$version'", "version='$result'")
+ String s = buildFile.getText().replaceFirst("version='$version'", "version='$result'")
- buildFile.setText(s)
- }
+ buildFile.setText(s)
+ }
}
artifacts {
- archives javadocJar
- archives sourcesJar
+ archives javadocJar
+ archives sourcesJar
}
afterEvaluate {
- tasks.javadoc.classpath += files(android.libraryVariants.collect { variant ->
- variant.javaCompileProvider.get().classpath
- })
+ tasks.javadoc.classpath += files(android.libraryVariants.collect { variant ->
+ variant.javaCompileProvider.get().classpath
+ })
}
diff --git a/personalization-sdk/src/main/AndroidManifest.xml b/personalization-sdk/src/main/AndroidManifest.xml
index b0ca77d9..0d8732bb 100644
--- a/personalization-sdk/src/main/AndroidManifest.xml
+++ b/personalization-sdk/src/main/AndroidManifest.xml
@@ -17,14 +17,7 @@
-
-
-
-
-
-
+
+
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/OnMessageListener.kt b/personalization-sdk/src/main/kotlin/com/personalization/OnMessageListener.kt
index 5e392e3f..a7fb38a6 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/OnMessageListener.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/OnMessageListener.kt
@@ -1,5 +1,7 @@
package com.personalization
+import com.personalization.features.notification.domain.model.NotificationData
+
fun interface OnMessageListener {
- fun onMessage(data: Map)
+ fun onMessage(data: NotificationData)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/RegisterManager.kt b/personalization-sdk/src/main/kotlin/com/personalization/RegisterManager.kt
index 35b2df90..018dd67e 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/RegisterManager.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/RegisterManager.kt
@@ -105,7 +105,7 @@ class RegisterManager @Inject constructor(
try {
val params = JSONObject()
params.put("tz", (TimeZone.getDefault().rawOffset / 3600000.0).toInt().toString())
- Log.i(TAG,"Sending init request with params: $params")
+ Log.i(TAG, "Sending init request with params: $params")
sendNetworkMethodUseCase.get("init", params, object : OnApiCallbackListener() {
@Volatile
private var attempt = 0
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/SDK.kt b/personalization-sdk/src/main/kotlin/com/personalization/SDK.kt
index d2507d12..919d065d 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/SDK.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/SDK.kt
@@ -14,9 +14,11 @@ import com.personalization.api.managers.ProductsManager
import com.personalization.api.managers.RecommendationManager
import com.personalization.api.managers.SearchManager
import com.personalization.api.managers.TrackEventManager
+import com.personalization.di.AppModule
import com.personalization.di.DaggerSdkComponent
-import com.personalization.notification.NotificationHandler
-import com.personalization.notification.NotificationHelper
+import com.personalization.features.notification.data.mapper.toNotificationData
+import com.personalization.features.notification.presentation.helpers.NotificationHelper
+import com.personalization.handlers.notifications.NotificationHandler
import com.personalization.sdk.domain.usecases.network.AddTaskToQueueUseCase
import com.personalization.sdk.domain.usecases.network.InitNetworkUseCase
import com.personalization.sdk.domain.usecases.network.SendNetworkMethodUseCase
@@ -93,6 +95,9 @@ open class SDK {
@Inject
lateinit var getAllNotificationsUseCase: GetAllNotificationsUseCase
+ @Inject
+ lateinit var notificationHelper: NotificationHelper
+
/**
* @param shopId Shop key
@@ -109,7 +114,8 @@ open class SDK {
notificationId: String,
autoSendPushToken: Boolean = true
) {
- val sdkComponent = DaggerSdkComponent.factory().create()
+ val sdkComponent =
+ DaggerSdkComponent.factory().create(AppModule(applicationContext = context))
sdkComponent.inject(this)
initPreferencesUseCase.invoke(
@@ -121,9 +127,6 @@ open class SDK {
segment = getPreferencesValueUseCase.getSegment()
- NotificationHelper.notificationType = notificationType
- NotificationHelper.notificationId = notificationId
-
notificationHandler.initialize(context)
initUserSettingsUseCase.invoke(
@@ -283,8 +286,15 @@ open class SDK {
* @param extras from data notification
*/
fun notificationClicked(extras: Bundle?) {
- notificationHandler.notificationClicked(extras = extras,
- sendAsync = { method, params -> sendNetworkMethodUseCase.postAsync(method, params) })
+ notificationHandler.notificationClicked(
+ extras = extras,
+ sendAsync = { method, params ->
+ sendNetworkMethodUseCase.postAsync(
+ method = method,
+ params = params
+ )
+ }
+ )
}
/**
@@ -805,8 +815,9 @@ open class SDK {
notificationReceived(remoteMessage.data)
onMessageListener?.let { listener ->
- val data = notificationHandler.prepareData(remoteMessage)
- listener.onMessage(data)
+ listener.onMessage(
+ data = remoteMessage.toNotificationData()
+ )
}
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/Search.kt b/personalization-sdk/src/main/kotlin/com/personalization/Search.kt
index 035f7aae..c618748a 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/Search.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/Search.kt
@@ -3,5 +3,5 @@ package com.personalization
import org.json.JSONObject
internal class Search(private val options: JSONObject) {
- var blank: JSONObject? = null
+ var blank: JSONObject? = null
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/api/ApiMethod.kt b/personalization-sdk/src/main/kotlin/com/personalization/api/ApiMethod.kt
index 77e41fcb..f807b7a9 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/api/ApiMethod.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/api/ApiMethod.kt
@@ -6,7 +6,7 @@ package com.personalization.api
)
sealed class ApiMethod(val type: String, val method: String) {
- class POST(method: String): ApiMethod(type = "POST", method = method)
+ class POST(method: String) : ApiMethod(type = "POST", method = method)
- class GET(method: String): ApiMethod(type = "GET", method = method)
+ class GET(method: String) : ApiMethod(type = "GET", method = method)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/api/managers/SearchManager.kt b/personalization-sdk/src/main/kotlin/com/personalization/api/managers/SearchManager.kt
index 3f4fd45e..6b33718a 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/api/managers/SearchManager.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/api/managers/SearchManager.kt
@@ -1,9 +1,9 @@
package com.personalization.api.managers
+import com.personalization.api.params.SearchParams
import com.personalization.api.responses.search.SearchBlankResponse
import com.personalization.api.responses.search.SearchFullResponse
import com.personalization.api.responses.search.SearchInstantResponse
-import com.personalization.api.params.SearchParams
interface SearchManager {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/di/AppModule.kt b/personalization-sdk/src/main/kotlin/com/personalization/di/AppModule.kt
new file mode 100644
index 00000000..44a5c32f
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/di/AppModule.kt
@@ -0,0 +1,21 @@
+package com.personalization.di
+
+import android.app.NotificationManager
+import android.content.Context
+import dagger.Module
+import dagger.Provides
+import javax.inject.Singleton
+
+@Module
+class AppModule(private val applicationContext: Context) {
+
+ @Singleton
+ @Provides
+ fun provideContext(): Context = applicationContext
+
+ @Singleton
+ @Provides
+ fun provideNotificationManager(context: Context): NotificationManager {
+ return context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/di/SdkComponent.kt b/personalization-sdk/src/main/kotlin/com/personalization/di/SdkComponent.kt
index f03bc758..d50fb695 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/di/SdkComponent.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/di/SdkComponent.kt
@@ -1,9 +1,10 @@
package com.personalization.di
import com.personalization.SDK
-import com.personalization.sdk.data.di.RepositoriesModule
+import com.personalization.features.notification.data.service.NotificationService
import com.personalization.sdk.data.di.DataSourcesModule
import com.personalization.sdk.data.di.ModelsModule
+import com.personalization.sdk.data.di.RepositoriesModule
import dagger.Component
import javax.inject.Singleton
@@ -13,15 +14,18 @@ import javax.inject.Singleton
DataSourcesModule::class,
RepositoriesModule::class,
ModelsModule::class,
- SdkModule::class
+ SdkModule::class,
+ AppModule::class
]
)
interface SdkComponent {
@Component.Factory
interface Factory {
- fun create(): SdkComponent
+ fun create(appModule: AppModule): SdkComponent
}
fun inject(sdk: SDK)
+
+ fun inject(service: NotificationService)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/di/SdkModule.kt b/personalization-sdk/src/main/kotlin/com/personalization/di/SdkModule.kt
index 1ae1df92..1717e24f 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/di/SdkModule.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/di/SdkModule.kt
@@ -7,6 +7,7 @@ import com.personalization.api.managers.RecommendationManager
import com.personalization.api.managers.SearchManager
import com.personalization.api.managers.TrackEventManager
import com.personalization.features.inAppNotification.impl.InAppNotificationManagerImpl
+import com.personalization.features.notification.domain.data.NotificationDataExtractor
import com.personalization.features.products.impl.ProductsManagerImpl
import com.personalization.features.recommendation.impl.RecommendationManagerImpl
import com.personalization.features.search.impl.SearchManagerImpl
@@ -94,4 +95,11 @@ class SdkModule {
@Singleton
@Provides
fun provideInAppNotificationManager(): InAppNotificationManager = InAppNotificationManagerImpl()
+
+ @Singleton
+ @Provides
+ fun provideNotificationDataExtractor(): NotificationDataExtractor {
+ return NotificationDataExtractor()
+ }
+
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/errors/actions.error.kt b/personalization-sdk/src/main/kotlin/com/personalization/errors/actions.error.kt
new file mode 100644
index 00000000..e93a4c10
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/errors/actions.error.kt
@@ -0,0 +1,18 @@
+package com.personalization.errors
+
+import android.util.Log
+
+class ActionsError(
+ private val tag: String,
+ private val functionName: String,
+ private val actionName: String,
+ private val message: String,
+) {
+
+ fun logError() {
+ Log.e(
+ /* tag = */ tag,
+ /* msg = */ "Error caught in $functionName : $message $actionName"
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/errors/emptyField.error.kt b/personalization-sdk/src/main/kotlin/com/personalization/errors/emptyField.error.kt
new file mode 100644
index 00000000..cfe9a853
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/errors/emptyField.error.kt
@@ -0,0 +1,17 @@
+package com.personalization.errors
+
+import android.util.Log
+
+class EmptyFieldError(
+ private val tag: String,
+ private val functionName: String,
+ private val message: String,
+) {
+
+ fun logError() {
+ Log.e(
+ /* tag = */ tag,
+ /* msg = */ "Error caught in $functionName : $message"
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/errors/network.error.kt b/personalization-sdk/src/main/kotlin/com/personalization/errors/network.error.kt
new file mode 100644
index 00000000..dd214068
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/errors/network.error.kt
@@ -0,0 +1,16 @@
+package com.personalization.errors
+
+import android.util.Log
+
+class NetworkError(
+ private val tag: String,
+ private val functionName: String
+) {
+
+ fun logError() {
+ Log.e(
+ /* tag = */ tag,
+ /* msg = */ "Error caught in $functionName : Network connection issue "
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/errors/parsing.error.kt b/personalization-sdk/src/main/kotlin/com/personalization/errors/parsing.error.kt
new file mode 100644
index 00000000..19f961a7
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/errors/parsing.error.kt
@@ -0,0 +1,17 @@
+package com.personalization.errors
+
+import android.util.Log
+
+class ParsingJsonError(
+ private val tag: String,
+ private val functionName: String,
+ private val message: String
+) {
+
+ fun logError() {
+ Log.e(
+ /* tag = */ tag,
+ /* msg = */ "Error caught in $functionName: $message"
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/errors/resourceLoading.error.kt b/personalization-sdk/src/main/kotlin/com/personalization/errors/resourceLoading.error.kt
new file mode 100644
index 00000000..874041b4
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/errors/resourceLoading.error.kt
@@ -0,0 +1,17 @@
+package com.personalization.errors
+
+import android.util.Log
+
+class ResourceLoadError(
+ private val tag: String,
+ private val functionName: String,
+ private val message: String
+) {
+
+ fun logError() {
+ Log.e(
+ /* tag = */ tag,
+ /* msg = */ "Error caught in $functionName: $message"
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/helpers/NotificationChannelHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/helpers/NotificationChannelHelper.kt
new file mode 100644
index 00000000..471ea1f1
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/helpers/NotificationChannelHelper.kt
@@ -0,0 +1,25 @@
+package com.personalization.features.notification.data.helpers
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Build
+import com.personalization.R
+
+object NotificationChannelHelper {
+
+ fun createNotificationChannel(context: Context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channelId = context.getString(R.string.notification_channel_id)
+ val channelName = context.getString(R.string.notification_channel_name)
+ val notificationManager = context.getSystemService(NotificationManager::class.java)
+ notificationManager?.createNotificationChannel(
+ /* channel = */ NotificationChannel(
+ /* id = */ channelId,
+ /* name = */ channelName,
+ /* importance = */ NotificationManager.IMPORTANCE_LOW
+ )
+ )
+ }
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/mapper/NotificationDataMapper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/mapper/NotificationDataMapper.kt
new file mode 100644
index 00000000..d42090b6
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/mapper/NotificationDataMapper.kt
@@ -0,0 +1,27 @@
+package com.personalization.features.notification.data.mapper
+
+import com.google.firebase.messaging.RemoteMessage
+import com.personalization.features.notification.domain.model.NotificationConstants
+import com.personalization.features.notification.domain.model.NotificationData
+
+fun RemoteMessage.toNotificationData(): NotificationData {
+ var title: String? = null
+ var body: String? = null
+ var imageUrl: String? = null
+
+ this.notification?.let { notification ->
+ title = notification.title?.takeIf { it.isNotEmpty() }
+ body = notification.body?.takeIf { it.isNotEmpty() }
+ imageUrl = notification.imageUrl?.toString()
+ }
+
+ val analyticsLabel: String? =
+ this.data[NotificationConstants.ANALYTICS_LABEL_FIELD]?.takeIf { it.isNotEmpty() }
+
+ return NotificationData(
+ title = title,
+ body = body,
+ images = imageUrl,
+ analyticsLabel = analyticsLabel
+ )
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/service/NotificationService.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/service/NotificationService.kt
new file mode 100644
index 00000000..28f3f00d
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/data/service/NotificationService.kt
@@ -0,0 +1,132 @@
+package com.personalization.features.notification.data.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import android.widget.Toast
+import com.personalization.di.AppModule
+import com.personalization.di.DaggerSdkComponent
+import com.personalization.features.notification.domain.model.NotificationConstants.CURRENT_IMAGE_INDEX
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_BODY
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_IMAGES
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_TITLE
+import com.personalization.features.notification.domain.model.NotificationData
+import com.personalization.features.notification.presentation.helpers.NotificationHelper
+import com.personalization.features.notification.presentation.helpers.NotificationImageHelper
+import com.personalization.resources.NotificationResources.NOTIFICATION_LOADING_DATA_ERROR
+import com.personalization.resources.NotificationResources.NOTIFICATION_LOADING_IMAGE_ERROR
+import java.io.IOException
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+class NotificationService : Service() {
+
+ @Inject
+ lateinit var notificationHelper: NotificationHelper
+
+ private val serviceJob = Job()
+ private val serviceScope = CoroutineScope(
+ context = Dispatchers.IO + serviceJob
+ )
+
+ override fun onCreate() {
+ super.onCreate()
+ DaggerSdkComponent.factory().create(
+ appModule = AppModule(
+ applicationContext = applicationContext
+ )
+ ).inject(service = this)
+ }
+
+ override fun onStartCommand(
+ intent: Intent?,
+ flags: Int,
+ startId: Int
+ ): Int {
+ val currentIndex = intent?.getIntExtra(CURRENT_IMAGE_INDEX, -1) ?: -1
+ val images = intent?.getStringExtra(NOTIFICATION_IMAGES)
+ val title = intent?.getStringExtra(NOTIFICATION_TITLE)
+ val body = intent?.getStringExtra(NOTIFICATION_BODY)
+
+ if (!isValidNotificationData(images, title, body, currentIndex)) {
+ showToast(
+ message = applicationContext.getString(
+ /* resId = */ NOTIFICATION_LOADING_DATA_ERROR
+ )
+ )
+ stopSelf(startId)
+ return START_NOT_STICKY
+ }
+
+ updateNotification(
+ images = images,
+ title = title,
+ body = body,
+ currentIndex = currentIndex,
+ startId = startId
+ )
+
+ return START_NOT_STICKY
+ }
+
+ override fun onBind(intent: Intent?): IBinder? = null
+
+ override fun onDestroy() {
+ super.onDestroy()
+ serviceJob.cancel()
+ }
+
+ private fun isValidNotificationData(
+ images: String?,
+ title: String?,
+ body: String?,
+ currentIndex: Int
+ ): Boolean {
+ return !images.isNullOrEmpty() && !title.isNullOrEmpty() && !body.isNullOrEmpty() && currentIndex >= 0
+ }
+
+ private fun updateNotification(
+ images: String?,
+ title: String?,
+ body: String?,
+ currentIndex: Int,
+ startId: Int
+ ) {
+ serviceScope.launch {
+ try {
+ val (loadedImages, hasError) = NotificationImageHelper.loadBitmaps(urls = images)
+ notificationHelper.createNotification(
+ context = this@NotificationService,
+ data = NotificationData(
+ title = title,
+ body = body,
+ images = images
+ ),
+ images = loadedImages,
+ currentImageIndex = currentIndex,
+ hasError = hasError
+ )
+ } catch (ioException: IOException) {
+ showToast(
+ message = applicationContext.getString(
+ /* resId = */ NOTIFICATION_LOADING_IMAGE_ERROR
+ )
+ )
+ ioException.printStackTrace()
+ } finally {
+ stopSelf(startId)
+ }
+ }
+ }
+
+ private fun showToast(message: String) {
+ Toast.makeText(
+ /* context = */ applicationContext,
+ /* text = */ message,
+ /* duration = */ Toast.LENGTH_SHORT
+ ).show()
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataExtractor.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataExtractor.kt
new file mode 100644
index 00000000..c1eed734
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataExtractor.kt
@@ -0,0 +1,16 @@
+package com.personalization.features.notification.domain.data
+
+import android.os.Bundle
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_ID
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_TYPE
+import javax.inject.Inject
+
+class NotificationDataExtractor @Inject constructor() {
+
+ fun extractData(extras: Bundle?): Pair {
+ val type = extras?.getString(NOTIFICATION_TYPE)
+ val code = extras?.getString(NOTIFICATION_ID)
+ return Pair(type, code)
+ }
+
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataSender.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataSender.kt
new file mode 100644
index 00000000..0d5ad60e
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/data/NotificationDataSender.kt
@@ -0,0 +1,19 @@
+package com.personalization.features.notification.domain.data
+
+import com.personalization.features.notification.domain.model.NotificationConstants.CODE_PARAM
+import com.personalization.features.notification.domain.model.NotificationConstants.TRACK_CLICKED
+import com.personalization.features.notification.domain.model.NotificationConstants.TYPE_PARAM
+import javax.inject.Inject
+import org.json.JSONObject
+
+class NotificationDataSender @Inject constructor() {
+
+ fun sendAsyncData(type: String, code: String, sendAsync: (String, JSONObject) -> Unit) {
+ val params = JSONObject().apply {
+ put(TYPE_PARAM, type)
+ put(CODE_PARAM, code)
+ }
+ sendAsync(TRACK_CLICKED, params)
+ }
+
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/helpers/NotificationClickProcessor.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/helpers/NotificationClickProcessor.kt
new file mode 100644
index 00000000..47bee2a6
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/helpers/NotificationClickProcessor.kt
@@ -0,0 +1,57 @@
+package com.personalization.features.notification.domain.helpers
+
+import android.os.Bundle
+import com.personalization.errors.EmptyFieldError
+import com.personalization.errors.ParsingJsonError
+import com.personalization.features.notification.domain.data.NotificationDataExtractor
+import com.personalization.features.notification.domain.data.NotificationDataSender
+import javax.inject.Inject
+import org.json.JSONException
+import org.json.JSONObject
+
+class NotificationClickProcessor @Inject constructor(
+ private val dataExtractor: NotificationDataExtractor,
+ private val dataSender: NotificationDataSender
+) {
+
+ fun processClick(
+ extras: Bundle?,
+ sendAsync: (String, JSONObject) -> Unit,
+ onResult: (type: String, code: String) -> Unit
+ ) {
+ val (type, code) = dataExtractor.extractData(extras = extras)
+
+ if (type == null || code == null) {
+ handleError(errorMessage = "Invalid notification data", extras = extras)
+ return
+ }
+
+ try {
+ dataSender.sendAsyncData(
+ type = type,
+ code = code,
+ sendAsync = sendAsync
+ )
+ onResult(type, code)
+ } catch (e: JSONException) {
+ ParsingJsonError(
+ tag = this@NotificationClickProcessor.javaClass.name,
+ functionName = "processClick",
+ message = e.message.orEmpty()
+ ).logError()
+ }
+ }
+
+ private fun handleError(errorMessage: String, extras: Bundle?) {
+ EmptyFieldError(
+ tag = TAG,
+ functionName = FUNCTION_NAME,
+ message = errorMessage + extras
+ ).logError()
+ }
+
+ companion object {
+ private const val TAG = "NotificationClickProcessor"
+ private const val FUNCTION_NAME = "processClick"
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationConstants.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationConstants.kt
new file mode 100644
index 00000000..c9b2d34f
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationConstants.kt
@@ -0,0 +1,18 @@
+package com.personalization.features.notification.domain.model
+
+object NotificationConstants {
+ const val NOTIFICATION_CHANNEL = "notification_channel"
+ const val ACTION_PREVIOUS_IMAGE = "ACTION_PREVIOUS_IMAGE"
+ const val CURRENT_IMAGE_INDEX = "current_image_index"
+ const val ANALYTICS_LABEL_FIELD = "analytics_label"
+ const val ACTION_NEXT_IMAGE = "ACTION_NEXT_IMAGE"
+ const val NOTIFICATION_TYPE = "NOTIFICATION_TYPE"
+ const val TRACK_CLICKED = "track/clicked"
+ const val NOTIFICATION_IMAGES = "images"
+ const val NOTIFICATION_TITLE = "title"
+ const val NOTIFICATION_BODY = "body"
+ const val TYPE_PARAM = "type"
+ const val CODE_PARAM = "code"
+
+ const val NOTIFICATION_ID = "NOTIFICATION_ID"
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationData.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationData.kt
new file mode 100644
index 00000000..593007bd
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/domain/model/NotificationData.kt
@@ -0,0 +1,8 @@
+package com.personalization.features.notification.domain.model
+
+data class NotificationData(
+ val title: String?,
+ val body: String?,
+ val images: String?,
+ val analyticsLabel: String? = null
+)
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationHelper.kt
new file mode 100644
index 00000000..9bd3b301
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationHelper.kt
@@ -0,0 +1,58 @@
+package com.personalization.features.notification.presentation.helpers
+
+import android.app.NotificationManager
+import android.content.Context
+import android.graphics.Bitmap
+import android.widget.RemoteViews
+import androidx.core.app.NotificationCompat
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_CHANNEL
+import com.personalization.features.notification.domain.model.NotificationData
+import com.personalization.resources.NotificationResources
+import javax.inject.Inject
+
+class NotificationHelper @Inject constructor(
+ private val notificationManager: NotificationManager
+) {
+
+ fun createNotification(
+ context: Context,
+ data: NotificationData,
+ images: List?,
+ currentImageIndex: Int = 0,
+ hasError: Boolean = false
+ ) {
+ val view = RemoteViews(
+ /* packageName = */ context.packageName,
+ /* layoutId = */ NotificationResources.NOTIFICATION_LAYOUT
+ )
+
+ NotificationTextHelper.setNotificationText(
+ customView = view,
+ data = data
+ )
+ NotificationImageHelper.displayImages(
+ customView = view,
+ images = images,
+ currentIndex = currentImageIndex
+ )
+ NotificationViewHelper.setNavigationActions(
+ customView = view,
+ context = context,
+ data = data,
+ currentIndex = currentImageIndex,
+ imageCount = images?.size ?: 0,
+ hasError = hasError
+ )
+
+ val notificationBuilder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
+ .setSmallIcon(NotificationResources.NOTIFICATION_ICON)
+ .setCustomContentView(view)
+ .setCustomBigContentView(view)
+ .setAutoCancel(true)
+
+ notificationManager.notify(
+ /* id = */ (data.title + data.body).hashCode(),
+ /* notification = */ notificationBuilder.build()
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationImageHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationImageHelper.kt
new file mode 100644
index 00000000..05422240
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationImageHelper.kt
@@ -0,0 +1,71 @@
+package com.personalization.features.notification.presentation.helpers
+
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.view.View
+import android.widget.RemoteViews
+import com.personalization.R
+import java.io.InputStream
+import java.net.URL
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.withContext
+
+object NotificationImageHelper {
+
+ fun displayImages(
+ customView: RemoteViews,
+ images: List?,
+ currentIndex: Int,
+ hasError: Boolean = false
+ ) {
+ if (hasError) {
+ customView.setViewVisibility(R.id.loadingProgressBar, View.GONE)
+ customView.setViewVisibility(R.id.retryButton, View.VISIBLE)
+ customView.setImageViewResource(R.id.largeImage, R.drawable.image_error)
+ customView.setViewVisibility(R.id.largeImage, View.VISIBLE)
+ } else if (!images.isNullOrEmpty() && currentIndex in images.indices) {
+ customView.setViewVisibility(R.id.loadingProgressBar, View.GONE)
+ customView.setViewVisibility(R.id.retryButton, View.GONE)
+ customView.setImageViewBitmap(R.id.smallImage, images[currentIndex])
+ customView.setImageViewBitmap(R.id.largeImage, images[currentIndex])
+ customView.setViewVisibility(R.id.actionContainer, View.VISIBLE)
+ customView.setViewVisibility(R.id.smallImage, View.VISIBLE)
+ customView.setViewVisibility(R.id.largeImage, View.VISIBLE)
+ } else {
+ customView.setViewVisibility(R.id.actionContainer, View.GONE)
+ customView.setViewVisibility(R.id.expandArrow, View.GONE)
+ customView.setViewVisibility(R.id.smallImage, View.GONE)
+ }
+ }
+
+ suspend fun loadBitmaps(urls: String?): Pair, Boolean> {
+
+ return withContext(Dispatchers.IO) {
+
+ if (urls == null) return@withContext Pair(emptyList(), true)
+
+ val urlArray = urls.split(",").toTypedArray()
+
+ var hasError = false
+
+ val bitmaps: List = coroutineScope {
+ urlArray.mapIndexed { index, url ->
+ async {
+ try {
+ val inputStream: InputStream = URL(url).openStream()
+ BitmapFactory.decodeStream(inputStream)
+ } catch (exception: Exception) {
+ hasError = true
+ null
+ }
+ }
+ }.awaitAll().filterNotNull()
+ }
+
+ Pair(bitmaps, hasError)
+ }
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationNavigationHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationNavigationHelper.kt
new file mode 100644
index 00000000..2cb0bca8
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationNavigationHelper.kt
@@ -0,0 +1,65 @@
+package com.personalization.features.notification.presentation.helpers
+
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import com.personalization.features.notification.data.service.NotificationService
+import com.personalization.features.notification.domain.model.NotificationConstants.CURRENT_IMAGE_INDEX
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_BODY
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_IMAGES
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_TITLE
+import com.personalization.features.notification.domain.model.NotificationData
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.math.abs
+
+object NotificationNavigationHelper {
+
+ private val requestCodeCounter = AtomicInteger(0)
+
+ fun createNavigationPendingIntent(
+ context: Context,
+ data: NotificationData,
+ newIndex: Int,
+ action: String
+ ): PendingIntent {
+ val intent = Intent(context, NotificationService::class.java).apply {
+ this.action = action
+ putExtra(CURRENT_IMAGE_INDEX, newIndex)
+ putExtra(NOTIFICATION_TITLE, data.title)
+ putExtra(NOTIFICATION_BODY, data.body)
+ putExtra(NOTIFICATION_IMAGES, data.images)
+ }
+
+ return PendingIntent.getService(
+ /* context = */ context,
+ /* requestCode = */ generateRequestCode(action, newIndex),
+ /* intent = */ intent,
+ /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ fun createRetryPendingIntent(
+ context: Context,
+ data: NotificationData
+ ): PendingIntent {
+ val retryIntent = Intent(context, NotificationService::class.java).apply {
+ putExtra(CURRENT_IMAGE_INDEX, 0)
+ putExtra(NOTIFICATION_IMAGES, data.images)
+ putExtra(NOTIFICATION_TITLE, data.title)
+ putExtra(NOTIFICATION_BODY, data.body)
+ }
+ return PendingIntent.getService(
+ context,
+ 0,
+ retryIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ }
+
+ private fun generateRequestCode(action: String, currentIndex: Int): Int {
+ val baseCode = "${action}_${currentIndex}".hashCode()
+ val uniqueCode = if (baseCode != Int.MIN_VALUE) abs(baseCode) else 0
+
+ return requestCodeCounter.incrementAndGet() + uniqueCode
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationTextHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationTextHelper.kt
new file mode 100644
index 00000000..570cb0f2
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationTextHelper.kt
@@ -0,0 +1,22 @@
+package com.personalization.features.notification.presentation.helpers
+
+import android.widget.RemoteViews
+import com.personalization.R
+import com.personalization.features.notification.domain.model.NotificationData
+
+object NotificationTextHelper {
+
+ fun setNotificationText(
+ customView: RemoteViews,
+ data: NotificationData
+ ) {
+ customView.setTextViewText(
+ /* viewId = */ R.id.title,
+ /* text = */ data.title
+ )
+ customView.setTextViewText(
+ /* viewId = */ R.id.body,
+ /* text = */ data.body
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationViewHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationViewHelper.kt
new file mode 100644
index 00000000..cbb7eedd
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/notification/presentation/helpers/NotificationViewHelper.kt
@@ -0,0 +1,95 @@
+package com.personalization.features.notification.presentation.helpers
+
+import android.content.Context
+import android.view.View
+import android.widget.RemoteViews
+import com.personalization.R
+import com.personalization.features.notification.domain.model.NotificationConstants.ACTION_NEXT_IMAGE
+import com.personalization.features.notification.domain.model.NotificationConstants.ACTION_PREVIOUS_IMAGE
+import com.personalization.features.notification.domain.model.NotificationData
+
+object NotificationViewHelper {
+
+ fun setNavigationActions(
+ customView: RemoteViews,
+ context: Context,
+ data: NotificationData,
+ currentIndex: Int,
+ imageCount: Int,
+ hasError: Boolean
+ ) {
+ setActionButton(
+ customView = customView,
+ context = context,
+ data = data,
+ actionId = R.id.action1,
+ action = ACTION_PREVIOUS_IMAGE,
+ newIndex = currentIndex - 1,
+ isVisible = currentIndex > 0
+ )
+
+ setActionButton(
+ customView = customView,
+ context = context,
+ data = data,
+ actionId = R.id.action2,
+ action = ACTION_NEXT_IMAGE,
+ newIndex = currentIndex + 1,
+ isVisible = currentIndex < imageCount - 1
+ )
+
+ setRetryButtonVisibility(
+ customView = customView,
+ context = context,
+ data = data,
+ hasError = hasError
+ )
+ }
+
+ private fun setActionButton(
+ customView: RemoteViews,
+ context: Context,
+ data: NotificationData,
+ actionId: Int,
+ action: String,
+ newIndex: Int,
+ isVisible: Boolean
+ ) {
+ val pendingIntent = NotificationNavigationHelper.createNavigationPendingIntent(
+ context = context,
+ data = data,
+ newIndex = newIndex,
+ action = action
+ )
+ customView.setOnClickPendingIntent(
+ /* viewId = */ actionId,
+ /* pendingIntent = */ pendingIntent
+ )
+ customView.setViewVisibility(
+ /* viewId = */ actionId,
+ /* visibility = */ if (isVisible) View.VISIBLE else View.GONE
+ )
+ }
+
+ private fun setRetryButtonVisibility(
+ customView: RemoteViews,
+ context: Context,
+ data: NotificationData,
+ hasError: Boolean
+ ) {
+ if (hasError) {
+ val retryPendingIntent = NotificationNavigationHelper.createRetryPendingIntent(
+ context = context,
+ data = data
+ )
+ customView.setOnClickPendingIntent(
+ /* viewId = */ R.id.retryButton,
+ /* pendingIntent = */ retryPendingIntent
+ )
+ }
+ customView.setViewVisibility(
+ /* viewId = */ R.id.retryButton,
+ /* visibility = */ if (hasError) View.VISIBLE else View.GONE
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/recommendation/impl/RecommendationManagerImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/recommendation/impl/RecommendationManagerImpl.kt
index 1a9c2540..ae154dc6 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/features/recommendation/impl/RecommendationManagerImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/recommendation/impl/RecommendationManagerImpl.kt
@@ -70,8 +70,16 @@ internal class RecommendationManagerImpl @Inject constructor(
)
}
- override fun getRecommendation(recommenderCode: String, params: Params, listener: OnApiCallbackListener) {
- sendNetworkMethodUseCase.getAsync("$GET_RECOMMENDATION_REQUEST/$recommenderCode", params.build(), listener)
+ override fun getRecommendation(
+ recommenderCode: String,
+ params: Params,
+ listener: OnApiCallbackListener
+ ) {
+ sendNetworkMethodUseCase.getAsync(
+ "$GET_RECOMMENDATION_REQUEST/$recommenderCode",
+ params.build(),
+ listener
+ )
}
companion object {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/search/impl/SearchManagerImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/search/impl/SearchManagerImpl.kt
index 87048011..6c0e6610 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/features/search/impl/SearchManagerImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/search/impl/SearchManagerImpl.kt
@@ -3,14 +3,14 @@ package com.personalization.features.search.impl
import com.google.gson.Gson
import com.personalization.Params
import com.personalization.api.OnApiCallbackListener
-import com.personalization.api.params.SearchParams
import com.personalization.api.managers.SearchManager
+import com.personalization.api.params.SearchParams
import com.personalization.api.responses.search.SearchBlankResponse
import com.personalization.api.responses.search.SearchFullResponse
import com.personalization.api.responses.search.SearchInstantResponse
import com.personalization.sdk.domain.usecases.network.SendNetworkMethodUseCase
-import org.json.JSONObject
import javax.inject.Inject
+import org.json.JSONObject
internal class SearchManagerImpl @Inject constructor(
private val sendNetworkMethodUseCase: SendNetworkMethodUseCase
@@ -25,7 +25,8 @@ internal class SearchManagerImpl @Inject constructor(
search(query, TYPE.FULL, searchParams, object : OnApiCallbackListener() {
override fun onSuccess(response: JSONObject?) {
response?.let {
- val searchFullResponse = Gson().fromJson(it.toString(), SearchFullResponse::class.java)
+ val searchFullResponse =
+ Gson().fromJson(it.toString(), SearchFullResponse::class.java)
onSearchFull(searchFullResponse)
}
}
@@ -44,12 +45,13 @@ internal class SearchManagerImpl @Inject constructor(
) {
val searchParams = SearchParams()
- if(locations != null) searchParams.put(LOCATIONS_PARAMETER, locations)
+ if (locations != null) searchParams.put(LOCATIONS_PARAMETER, locations)
search(query, TYPE.INSTANT, searchParams, object : OnApiCallbackListener() {
override fun onSuccess(response: JSONObject?) {
response?.let {
- val searchInstantResponse = Gson().fromJson(it.toString(), SearchInstantResponse::class.java)
+ val searchInstantResponse =
+ Gson().fromJson(it.toString(), SearchInstantResponse::class.java)
onSearchInstant(searchInstantResponse)
}
}
@@ -64,18 +66,22 @@ internal class SearchManagerImpl @Inject constructor(
onSearchBlank: (SearchBlankResponse) -> Unit,
onError: (Int, String?) -> Unit
) {
- sendNetworkMethodUseCase.get(BLANK_SEARCH_REQUEST, Params().build(), object : OnApiCallbackListener() {
- override fun onSuccess(response: JSONObject?) {
- response?.let {
- val searchBlankResponse = Gson().fromJson(it.toString(), SearchBlankResponse::class.java)
- onSearchBlank(searchBlankResponse)
+ sendNetworkMethodUseCase.get(
+ BLANK_SEARCH_REQUEST,
+ Params().build(),
+ object : OnApiCallbackListener() {
+ override fun onSuccess(response: JSONObject?) {
+ response?.let {
+ val searchBlankResponse =
+ Gson().fromJson(it.toString(), SearchBlankResponse::class.java)
+ onSearchBlank(searchBlankResponse)
+ }
}
- }
- override fun onError(code: Int, msg: String?) {
- onError(code, msg)
- }
- })
+ override fun onError(code: Int, msg: String?) {
+ onError(code, msg)
+ }
+ })
}
private fun search(
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/features/trackEvent/impl/TrackEventManagerImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/features/trackEvent/impl/TrackEventManagerImpl.kt
index 559ac0c6..7fe5102c 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/features/trackEvent/impl/TrackEventManagerImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/features/trackEvent/impl/TrackEventManagerImpl.kt
@@ -47,13 +47,27 @@ internal class TrackEventManagerImpl @Inject constructor(
) {
val params = Params()
params.put(EVENT_PARAMETER, event)
- if (email != null) { params.put(EMAIL_PARAMETER, email) }
- if (phone != null) { params.put(PHONE_PARAMETER, phone) }
- if (loyaltyId != null) { params.put(LOYALTY_ID_PARAMETER, loyaltyId) }
- if (externalId != null) { params.put(EXTERNAL_ID_PARAMETER, externalId) }
- if (category != null) { params.put(CATEGORY_PARAMETER, category) }
- if (label != null) { params.put(LABEL_PARAMETER, label) }
- if (value != null) { params.put(VALUE_PARAMETER, value) }
+ if (email != null) {
+ params.put(EMAIL_PARAMETER, email)
+ }
+ if (phone != null) {
+ params.put(PHONE_PARAMETER, phone)
+ }
+ if (loyaltyId != null) {
+ params.put(LOYALTY_ID_PARAMETER, loyaltyId)
+ }
+ if (externalId != null) {
+ params.put(EXTERNAL_ID_PARAMETER, externalId)
+ }
+ if (category != null) {
+ params.put(CATEGORY_PARAMETER, category)
+ }
+ if (label != null) {
+ params.put(LABEL_PARAMETER, label)
+ }
+ if (value != null) {
+ params.put(VALUE_PARAMETER, value)
+ }
sendNetworkMethodUseCase.postAsync(CUSTOM_PUSH_REQUEST, params.build(), listener)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/handlers/notifications/NotificationHandler.kt b/personalization-sdk/src/main/kotlin/com/personalization/handlers/notifications/NotificationHandler.kt
new file mode 100644
index 00000000..2970a6fb
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/handlers/notifications/NotificationHandler.kt
@@ -0,0 +1,39 @@
+package com.personalization.handlers.notifications
+
+import android.content.Context
+import android.os.Bundle
+import com.personalization.features.notification.data.helpers.NotificationChannelHelper
+import com.personalization.features.notification.domain.helpers.NotificationClickProcessor
+import com.personalization.sdk.domain.usecases.notification.UpdateNotificationSourceUseCase
+import javax.inject.Inject
+import org.json.JSONObject
+
+class NotificationHandler @Inject constructor(
+ private val updateSourceUseCase: UpdateNotificationSourceUseCase,
+ private val notificationClickProcessor: NotificationClickProcessor
+) {
+
+ private lateinit var context: Context
+
+ internal fun initialize(context: Context) {
+ this.context = context
+ createNotificationChannel()
+ }
+
+ private fun createNotificationChannel() {
+ NotificationChannelHelper.createNotificationChannel(context = context)
+ }
+
+ fun notificationClicked(
+ extras: Bundle?,
+ sendAsync: (String, JSONObject) -> Unit
+ ) {
+ notificationClickProcessor.processClick(
+ extras = extras,
+ sendAsync = sendAsync,
+ onResult = { type, code ->
+ updateSourceUseCase(type = type, id = code)
+ }
+ )
+ }
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/inAppNotification/view/component/button/Button.kt b/personalization-sdk/src/main/kotlin/com/personalization/inAppNotification/view/component/button/Button.kt
index 0ff02e3d..c886757a 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/inAppNotification/view/component/button/Button.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/inAppNotification/view/component/button/Button.kt
@@ -67,6 +67,7 @@ class Button @JvmOverloads constructor(
typedArray.recycle()
}
+
private val Int.dpToPx: Int
get() = (this * context.resources.displayMetrics.density).toInt()
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationBroadcastReceiver.kt b/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationBroadcastReceiver.kt
deleted file mode 100644
index 6a19ee3d..00000000
--- a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationBroadcastReceiver.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.personalization.notification
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import androidx.work.Data
-import androidx.work.OneTimeWorkRequest
-import androidx.work.WorkManager
-import com.personalization.SDK
-import com.personalization.notification.NotificationHelper.ACTION_NEXT_IMAGE
-import com.personalization.notification.NotificationHelper.ACTION_PREVIOUS_IMAGE
-import com.personalization.notification.NotificationHelper.CURRENT_IMAGE_INDEX
-import com.personalization.notification.NotificationHelper.NOTIFICATION_BODY
-import com.personalization.notification.NotificationHelper.NOTIFICATION_IMAGES
-import com.personalization.notification.NotificationHelper.NOTIFICATION_TITLE
-
-class NotificationBroadcastReceiver : BroadcastReceiver() {
-
- override fun onReceive(context: Context, intent: Intent) {
- val action = intent.action
-
- val currentIndex = intent.getIntExtra(CURRENT_IMAGE_INDEX, 0)
- val images = intent.getStringExtra(NOTIFICATION_IMAGES)
- val title = intent.getStringExtra(NOTIFICATION_TITLE)
- val body = intent.getStringExtra(NOTIFICATION_BODY)
-
- when (action) {
- ACTION_NEXT_IMAGE, ACTION_PREVIOUS_IMAGE -> {
- if (!images.isNullOrEmpty() && !title.isNullOrEmpty() && !body.isNullOrEmpty()) {
- val inputData = Data.Builder()
- .putString(NOTIFICATION_IMAGES, images)
- .putString(NOTIFICATION_TITLE, title)
- .putString(NOTIFICATION_BODY, body)
- .putInt(CURRENT_IMAGE_INDEX, currentIndex)
- .build()
-
- val updateNotificationWork = OneTimeWorkRequest.Builder(
- workerClass = UpdateNotificationWorker::class.java
- ).setInputData(inputData).build()
-
- WorkManager.getInstance(context).enqueue(updateNotificationWork)
- } else {
- SDK.error("Error caught in onReceive because one of the fields is empty or null")
- }
- }
-
- else -> SDK.error("Error caught in onReceive due to unknown action $action")
- }
- }
-}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHandler.kt b/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHandler.kt
deleted file mode 100644
index f4b9068e..00000000
--- a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHandler.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.personalization.notification
-
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.content.Context
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import com.google.firebase.messaging.RemoteMessage
-import com.personalization.R
-import com.personalization.sdk.domain.usecases.notification.UpdateNotificationSourceUseCase
-import org.json.JSONException
-import org.json.JSONObject
-import javax.inject.Inject
-
-class NotificationHandler @Inject constructor(
- private val updateSourceUseCase: UpdateNotificationSourceUseCase
-) {
-
- private lateinit var context: Context
-
- internal fun initialize(context: Context) {
- this.context = context
-
- createNotificationChannel()
- }
-
- private fun createNotificationChannel() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val channelId = context.getString(R.string.notification_channel_id)
- val channelName = context.getString(R.string.notification_channel_name)
- val notificationManager = context.getSystemService(
- NotificationManager::class.java
- )
- notificationManager?.createNotificationChannel(
- /* channel = */ NotificationChannel(
- /* id = */ channelId,
- /* name = */ channelName,
- /* importance = */ NotificationManager.IMPORTANCE_LOW
- )
- )
- }
- }
-
- fun notificationClicked(
- extras: Bundle?,
- sendAsync: (String, JSONObject) -> Unit
- ) {
- if (extras == null) {
- return
- } else {
- val type = extras.getString(NOTIFICATION_TYPE, null)
- val code = extras.getString(NOTIFICATION_ID, null)
-
- if (type != null && code != null) {
- val params = JSONObject()
- try {
- params.put(TYPE_PARAM, type)
- params.put(CODE_PARAM, code)
- sendAsync(TRACK_CLICKED, params)
-
- updateSourceUseCase(
- type = type,
- id = code
- )
- } catch (e: JSONException) {
- Log.e(TAG, e.message, e)
- }
- }
- }
- }
-
- fun prepareData(remoteMessage: RemoteMessage): MutableMap {
- val data: MutableMap = HashMap(remoteMessage.data)
- remoteMessage.notification?.let { notification ->
- addNotificationData(notification = notification, data = data)
- }
- data[IMAGES_FIELD]?.takeIf { it.isNotEmpty() }?.let { data[IMAGES_FIELD] = it }
- data[ANALYTICS_LABEL_FIELD]?.takeIf { it.isNotEmpty() }?.let { data[ANALYTICS_LABEL_FIELD] = it }
- return data
- }
-
- private fun addNotificationData(
- notification: RemoteMessage.Notification,
- data: MutableMap
- ) {
- notification.title?.takeIf { it.isNotEmpty() }?.let { data[TITLE_FIELD] = it }
- notification.body?.takeIf { it.isNotEmpty() }?.let { data[BODY_FIELD] = it }
- notification.imageUrl?.let { data[IMAGE_FIELD] = it.toString() }
- }
-
- private fun error(message: String?, exception: Exception? = null) {
- Log.e(TAG, message, exception)
- }
-
- companion object {
- private const val NOTIFICATION_TYPE = "NOTIFICATION_TYPE"
- private const val NOTIFICATION_ID = "NOTIFICATION_ID"
- private const val TRACK_CLICKED = "track/clicked"
- private const val TAG = "NotificationHandler"
- private const val IMAGES_FIELD = "images"
- private const val TITLE_FIELD = "title"
- private const val IMAGE_FIELD = "image"
- private const val ANALYTICS_LABEL_FIELD = "analytics_label"
- private const val BODY_FIELD = "body"
- private const val TYPE_PARAM = "type"
- private const val CODE_PARAM = "code"
- }
-}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHelper.kt b/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHelper.kt
deleted file mode 100644
index 2a8cfb55..00000000
--- a/personalization-sdk/src/main/kotlin/com/personalization/notification/NotificationHelper.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-package com.personalization.notification
-
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import androidx.core.app.NotificationCompat
-import com.personalization.R
-import com.personalization.SDK
-import java.io.IOException
-import java.io.InputStream
-import java.net.URL
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-
-object NotificationHelper {
-
- const val TAG = "NotificationHelper"
-
- private const val NOTIFICATION_CHANNEL = "notification_channel"
- const val ACTION_PREVIOUS_IMAGE = "ACTION_PREVIOUS_IMAGE"
- const val CURRENT_IMAGE_INDEX = "current_image_index"
- const val ACTION_NEXT_IMAGE = "ACTION_NEXT_IMAGE"
- const val NOTIFICATION_IMAGES = "images"
- const val NOTIFICATION_TITLE = "title"
- const val NOTIFICATION_BODY = "body"
-
- var notificationType: String = "NOTIFICATION_TYPE"
- var notificationId: String = "NOTIFICATION_ID"
-
- private val requestCodeGenerator = RequestCodeGenerator
-
- fun createNotification(
- context: Context,
- data: Map,
- images: List?,
- currentIndex: Int
- ) {
- val intent = createNotificationIntent(
- context = context,
- data = data,
- currentIndex = currentIndex
- )
-
- val pendingIntent = PendingIntent.getActivity(
- /* context = */ context,
- /* requestCode = */ requestCodeGenerator.generateRequestCode(
- action = intent.action.orEmpty(),
- currentIndex = currentIndex
- ),
- /* intent = */ intent,
- /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
-
- val notificationBuilder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
- .setContentTitle(data[NOTIFICATION_TITLE])
- .setContentText(data[NOTIFICATION_BODY])
- .setSmallIcon(android.R.drawable.stat_notify_chat)
- .setAutoCancel(true)
- .setContentIntent(pendingIntent)
-
- if (!images.isNullOrEmpty() && currentIndex >= 0 && currentIndex < images.size) {
- val currentImage = images[currentIndex]
-
- notificationBuilder.setLargeIcon(currentImage)
- .setStyle(
- NotificationCompat.BigPictureStyle().bigPicture(currentImage)
- )
-
- if (currentIndex > 0) {
- val prevIntent = createNotificationIntent(
- context = context,
- data = data,
- currentIndex = currentIndex - 1
- )
- val prevPendingIntent = PendingIntent.getBroadcast(
- /* context = */ context,
- /* requestCode = */ requestCodeGenerator.generateRequestCode(
- action = prevIntent.action.orEmpty(),
- currentIndex = currentIndex - 1
- ),
- /* intent = */ prevIntent,
- /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- notificationBuilder.addAction(
- /* action = */ NotificationCompat.Action.Builder(
- /* icon = */ android.R.drawable.ic_media_previous,
- /* title = */ context.getString(R.string.notification_button_back),
- /* intent = */ prevPendingIntent
- ).build()
- )
- }
-
- if (currentIndex < images.size - 1) {
- val nextIntent = createNotificationIntent(
- context = context,
- data = data,
- currentIndex = currentIndex + 1
- )
- val nextPendingIntent = PendingIntent.getBroadcast(
- /* context = */ context,
- /* requestCode = */ requestCodeGenerator.generateRequestCode(
- action = nextIntent.action.orEmpty(),
- currentIndex = currentIndex + 1
- ),
- /* intent = */ nextIntent,
- /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- notificationBuilder.addAction(
- /* action = */ NotificationCompat.Action.Builder(
- /* icon = */ android.R.drawable.ic_media_next,
- /* title = */ context.getString(R.string.notification_button_forward),
- /* intent = */ nextPendingIntent
- ).build()
- )
- }
- } else {
- notificationBuilder.setStyle(
- NotificationCompat.BigTextStyle().bigText(data[NOTIFICATION_BODY])
- )
- }
-
- val notificationManager =
- context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
- when {
- notificationManager != null -> notificationManager.notify(
- /* id = */ notificationId.hashCode(),
- /* notification = */ notificationBuilder.build()
- )
- else -> SDK.error("NotificationManager not available")
- }
- }
-
- private fun createNotificationIntent(
- context: Context,
- data: Map,
- currentIndex: Int
- ): Intent = Intent(context, NotificationBroadcastReceiver::class.java).apply {
- putExtra(NOTIFICATION_IMAGES, data[NOTIFICATION_IMAGES])
- putExtra(NOTIFICATION_TITLE, data[NOTIFICATION_TITLE])
- putExtra(NOTIFICATION_BODY, data[NOTIFICATION_BODY])
- putExtra(notificationType, data[notificationType])
- putExtra(notificationId, data[notificationId])
- putExtra(CURRENT_IMAGE_INDEX, currentIndex)
-
- action = when (currentIndex) {
- 0 -> ACTION_NEXT_IMAGE
- else -> ACTION_PREVIOUS_IMAGE
- }
- }
-
- suspend fun loadBitmaps(urls: String?): List {
- val bitmaps = mutableListOf()
- if (urls != null) {
- val urlArray = urls.split(",").toTypedArray()
- withContext(Dispatchers.IO) {
- for (url in urlArray) {
- try {
- val inputStream: InputStream = URL(url).openStream()
- bitmaps.add(BitmapFactory.decodeStream(inputStream))
- } catch (ioException: IOException) {
- SDK.error("Error caught in load bitmaps", ioException)
- }
- }
- }
- }
- return bitmaps
- }
-}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/notification/RequestCodeGenerator.kt b/personalization-sdk/src/main/kotlin/com/personalization/notification/RequestCodeGenerator.kt
deleted file mode 100644
index 6653953c..00000000
--- a/personalization-sdk/src/main/kotlin/com/personalization/notification/RequestCodeGenerator.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.personalization.notification
-
-import kotlin.math.abs
-
-object RequestCodeGenerator {
-
- /**
- * Create a unique requestCode based on the hashcode of the combination of action and currentIndex
- * */
- fun generateRequestCode(action: String, currentIndex: Int): Int {
- val uniqueKey = "${action}_${currentIndex}".hashCode()
- return if (uniqueKey != Int.MIN_VALUE) abs(uniqueKey) else 0
- }
-}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/notification/UpdateNotificationWorker.kt b/personalization-sdk/src/main/kotlin/com/personalization/notification/UpdateNotificationWorker.kt
deleted file mode 100644
index b2b3ae4e..00000000
--- a/personalization-sdk/src/main/kotlin/com/personalization/notification/UpdateNotificationWorker.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.personalization.notification
-
-import android.content.Context
-import androidx.work.CoroutineWorker
-import androidx.work.WorkerParameters
-import com.personalization.SDK
-import java.io.IOException
-
-class UpdateNotificationWorker(
- context: Context,
- workerParams: WorkerParameters
-) : CoroutineWorker(context, workerParams) {
-
- override suspend fun doWork(): Result {
- val context = applicationContext
-
- val newIndex = inputData.getInt(NotificationHelper.CURRENT_IMAGE_INDEX, 0)
- val images = inputData.getString(NotificationHelper.NOTIFICATION_IMAGES)
- val title = inputData.getString(NotificationHelper.NOTIFICATION_TITLE)
- val body = inputData.getString(NotificationHelper.NOTIFICATION_BODY)
-
- return if (images.isNullOrEmpty() || title.isNullOrEmpty() || body.isNullOrEmpty()) {
- SDK.error("Invalid input data: images=$images, title=$title, body=$body")
-
- Result.failure()
- } else {
-
- val data = mapOf(
- NotificationHelper.NOTIFICATION_IMAGES to images,
- NotificationHelper.NOTIFICATION_TITLE to title,
- NotificationHelper.NOTIFICATION_BODY to body
- )
-
- try {
- val loadedImages = NotificationHelper.loadBitmaps(urls = images)
- NotificationHelper.createNotification(
- context = context,
- data = data,
- images = loadedImages,
- currentIndex = newIndex
- )
-
- Result.success()
- } catch (ioException: IOException) {
- SDK.error("Error caught in updateNotification", ioException)
- Result.failure()
- }
- }
- }
-}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/resources/NotificationResources.kt b/personalization-sdk/src/main/kotlin/com/personalization/resources/NotificationResources.kt
new file mode 100644
index 00000000..b4075525
--- /dev/null
+++ b/personalization-sdk/src/main/kotlin/com/personalization/resources/NotificationResources.kt
@@ -0,0 +1,10 @@
+package com.personalization.resources
+
+import com.personalization.R
+
+object NotificationResources {
+ val NOTIFICATION_LAYOUT = R.layout.custom_notification
+ val NOTIFICATION_ICON = R.drawable.ic_notification_logo
+ val NOTIFICATION_LOADING_DATA_ERROR = R.string.notification_data_loading_error
+ val NOTIFICATION_LOADING_IMAGE_ERROR = R.string.notification_image_loading_error
+}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/di/DataSourcesModule.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/di/DataSourcesModule.kt
index 68deb049..39a67d22 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/di/DataSourcesModule.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/di/DataSourcesModule.kt
@@ -43,6 +43,6 @@ class DataSourcesModule {
fun provideNotificationDataSource(
preferencesDataSource: PreferencesDataSource
) = NotificationDataSource(
- preferencesDataSource = preferencesDataSource
- )
+ preferencesDataSource = preferencesDataSource
+ )
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/network/NetworkRepositoryImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/network/NetworkRepositoryImpl.kt
index def7abd7..f642d09f 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/network/NetworkRepositoryImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/network/NetworkRepositoryImpl.kt
@@ -8,10 +8,6 @@ import com.personalization.sdk.domain.models.NetworkMethod
import com.personalization.sdk.domain.repositories.NetworkRepository
import com.personalization.sdk.domain.repositories.NotificationRepository
import com.personalization.sdk.domain.repositories.UserSettingsRepository
-import org.json.JSONArray
-import org.json.JSONException
-import org.json.JSONObject
-import org.json.JSONTokener
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.IOException
@@ -24,6 +20,10 @@ import java.net.URL
import java.nio.charset.StandardCharsets
import java.util.Collections
import javax.inject.Inject
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.json.JSONTokener
class NetworkRepositoryImpl @Inject constructor(
private val networkDataSourceFactory: DataSourcesModule.NetworkDataSourceFactory,
@@ -125,7 +125,9 @@ class NetworkRepositoryImpl @Inject constructor(
private fun sendAsync(sendFunction: () -> Unit) {
val thread = Thread(sendFunction)
- if (userSettingsRepository.getDid().isNotEmpty() && userSettingsRepository.getIsInitialized()) {
+ if (userSettingsRepository.getDid()
+ .isNotEmpty() && userSettingsRepository.getIsInitialized()
+ ) {
thread.start()
} else {
addTaskToQueue(thread)
@@ -164,7 +166,8 @@ class NetworkRepositoryImpl @Inject constructor(
) {
userSettingsRepository.updateSidLastActTime()
- val notificationSource = notificationRepository.getNotificationSource(NetworkDataSource.sourceTimeDuration)
+ val notificationSource =
+ notificationRepository.getNotificationSource(NetworkDataSource.sourceTimeDuration)
try {
val newParams = userSettingsRepository.addParams(
@@ -230,7 +233,7 @@ class NetworkRepositoryImpl @Inject constructor(
networkMethod: NetworkMethod,
params: JSONObject
): Uri {
- if(networkDataSource == null) throw Exception("Network not initialized.")
+ if (networkDataSource == null) throw Exception("Network not initialized.")
val builder = Uri.parse(networkDataSource!!.baseUrl + networkMethod.method).buildUpon()
@@ -246,8 +249,8 @@ class NetworkRepositoryImpl @Inject constructor(
private fun getUrl(
networkMethod: NetworkMethod,
buildUri: Uri
- ) : URL {
- if(networkDataSource == null) throw Exception("Network not initialized.")
+ ): URL {
+ if (networkDataSource == null) throw Exception("Network not initialized.")
return if (networkMethod is NetworkMethod.POST) {
URL(networkDataSource!!.baseUrl + networkMethod.method)
@@ -260,7 +263,7 @@ class NetworkRepositoryImpl @Inject constructor(
networkMethod: NetworkMethod,
url: URL,
params: JSONObject
- ) : HttpURLConnection {
+ ): HttpURLConnection {
val connection = url.openConnection() as HttpURLConnection
connection.setRequestProperty("User-Agent", SDK.userAgent())
connection.requestMethod = networkMethod.type
@@ -270,7 +273,8 @@ class NetworkRepositoryImpl @Inject constructor(
connection.setRequestProperty("Content-Type", "application/json")
connection.doOutput = true
connection.doInput = true
- val os = BufferedWriter(OutputStreamWriter(connection.outputStream, StandardCharsets.UTF_8))
+ val os =
+ BufferedWriter(OutputStreamWriter(connection.outputStream, StandardCharsets.UTF_8))
os.write(params.toString())
os.flush()
os.close()
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/notification/NotificationRepositoryImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/notification/NotificationRepositoryImpl.kt
index a7e0dfbc..042f46a1 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/notification/NotificationRepositoryImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/notification/NotificationRepositoryImpl.kt
@@ -8,8 +8,8 @@ import com.personalization.sdk.data.models.params.GetAllNotificationsParams
import com.personalization.sdk.data.utils.ParamsEnumUtils.addOptionalParam
import com.personalization.sdk.domain.models.NotificationSource
import com.personalization.sdk.domain.repositories.NotificationRepository
-import org.json.JSONObject
import javax.inject.Inject
+import org.json.JSONObject
class NotificationRepositoryImpl @Inject constructor(
private val notificationDataSource: NotificationDataSource,
@@ -61,11 +61,12 @@ class NotificationRepositoryImpl @Inject constructor(
override fun getAllNotificationListener(
onGetAllNotifications: (GetAllNotificationsResponse) -> Unit,
onError: (Int, String?) -> Unit
- ) : OnApiCallbackListener =
+ ): OnApiCallbackListener =
object : OnApiCallbackListener() {
override fun onSuccess(response: JSONObject?) {
response?.let {
- val getAllNotificationsResponse = Gson().fromJson(it.toString(), GetAllNotificationsResponse::class.java)
+ val getAllNotificationsResponse =
+ Gson().fromJson(it.toString(), GetAllNotificationsResponse::class.java)
onGetAllNotifications(getAllNotificationsResponse)
}
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/preferences/PreferencesDataSource.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/preferences/PreferencesDataSource.kt
index 2a9eb90f..6ea900b7 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/preferences/PreferencesDataSource.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/preferences/PreferencesDataSource.kt
@@ -20,7 +20,9 @@ class PreferencesDataSource {
internal fun getToken(): String = getValue(TOKEN_KEY, DEFAULT_TOKEN)
internal fun saveToken(value: String) = saveValue(TOKEN_KEY, value)
- internal fun getLastPushTokenDate() = getValue(LAST_PUSH_TOKEN_DATE_KEY, DEFAULT_LAST_PUSH_TOKEN_DATE)
+ internal fun getLastPushTokenDate() =
+ getValue(LAST_PUSH_TOKEN_DATE_KEY, DEFAULT_LAST_PUSH_TOKEN_DATE)
+
internal fun saveLastPushTokenDate(value: Long) = saveValue(LAST_PUSH_TOKEN_DATE_KEY, value)
internal fun getSegment(): String {
@@ -28,10 +30,13 @@ class PreferencesDataSource {
return getValue(field, DEFAULT_SEGMENT)
}
- internal fun getValue(field: String, defaultValue: String): String = sharedPreferences?.getString(field, defaultValue) ?: defaultValue
- internal fun getValue(field: String, defaultValue: Long): Long = sharedPreferences?.getLong(field, defaultValue) ?: defaultValue
+ internal fun getValue(field: String, defaultValue: String): String =
+ sharedPreferences?.getString(field, defaultValue) ?: defaultValue
+
+ internal fun getValue(field: String, defaultValue: Long): Long =
+ sharedPreferences?.getLong(field, defaultValue) ?: defaultValue
- internal fun saveValue(field: String, value: T) {
+ internal fun saveValue(field: String, value: T) {
val putEditor = sharedPreferences?.let { sharedPreferences ->
with(sharedPreferences.edit()) {
when (value) {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsDataSource.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsDataSource.kt
index 7c99c261..9a5da718 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsDataSource.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsDataSource.kt
@@ -45,8 +45,11 @@ class UserSettingsDataSource @AssistedInject constructor(
return params
}
- internal fun getSidLastActTime(): Long = preferencesDataSource.getValue(SID_LAST_ACT_KEY, DEFAULT_SID_LAST_ACT_TIME)
- internal fun saveSidLastActTime(value: Long) = preferencesDataSource.saveValue(SID_LAST_ACT_KEY, value)
+ internal fun getSidLastActTime(): Long =
+ preferencesDataSource.getValue(SID_LAST_ACT_KEY, DEFAULT_SID_LAST_ACT_TIME)
+
+ internal fun saveSidLastActTime(value: Long) =
+ preferencesDataSource.saveValue(SID_LAST_ACT_KEY, value)
internal fun getSid(): String = preferencesDataSource.getValue(SID_KEY, DEFAULT_SID)
internal fun saveSid(value: String) = preferencesDataSource.saveValue(SID_KEY, value)
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsRepositoryImpl.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsRepositoryImpl.kt
index 8c9dc602..05c8f854 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsRepositoryImpl.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/data/repositories/userSettings/UserSettingsRepositoryImpl.kt
@@ -3,8 +3,8 @@ package com.personalization.sdk.data.repositories.userSettings
import com.personalization.sdk.data.di.DataSourcesModule
import com.personalization.sdk.domain.models.NotificationSource
import com.personalization.sdk.domain.repositories.UserSettingsRepository
-import org.json.JSONObject
import javax.inject.Inject
+import org.json.JSONObject
class UserSettingsRepositoryImpl @Inject constructor(
private val userSettingsDataSourceFactory: DataSourcesModule.UserSettingsDataSourceFactory,
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/models/NetworkMethod.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/models/NetworkMethod.kt
index 4e1e738d..b1d286b8 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/models/NetworkMethod.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/models/NetworkMethod.kt
@@ -2,7 +2,7 @@ package com.personalization.sdk.domain.models
sealed class NetworkMethod(val type: String, val method: String) {
- class POST(method: String): NetworkMethod(type = "POST", method = method)
+ class POST(method: String) : NetworkMethod(type = "POST", method = method)
- class GET(method: String): NetworkMethod(type = "GET", method = method)
+ class GET(method: String) : NetworkMethod(type = "GET", method = method)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/repositories/RecommendationRepository.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/repositories/RecommendationRepository.kt
index df4a7cbe..0c669328 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/repositories/RecommendationRepository.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/repositories/RecommendationRepository.kt
@@ -4,6 +4,6 @@ import com.personalization.sdk.domain.models.RecommendedBy
interface RecommendationRepository {
- fun getRecommendedBy() : RecommendedBy?
+ fun getRecommendedBy(): RecommendedBy?
fun setRecommendedBy(recommendedBy: RecommendedBy?)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/network/SendNetworkMethodUseCase.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/network/SendNetworkMethodUseCase.kt
index b76dd58a..3d5b4bb2 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/network/SendNetworkMethodUseCase.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/network/SendNetworkMethodUseCase.kt
@@ -2,8 +2,8 @@ package com.personalization.sdk.domain.usecases.network
import com.personalization.api.OnApiCallbackListener
import com.personalization.sdk.domain.repositories.NetworkRepository
-import org.json.JSONObject
import javax.inject.Inject
+import org.json.JSONObject
class SendNetworkMethodUseCase @Inject constructor(
private val networkRepository: NetworkRepository
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/GetAllNotificationsUseCase.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/GetAllNotificationsUseCase.kt
index 8b4e25f9..d68326cb 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/GetAllNotificationsUseCase.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/GetAllNotificationsUseCase.kt
@@ -8,10 +8,10 @@ import com.personalization.api.responses.notifications.GetAllNotificationsRespon
import com.personalization.sdk.domain.repositories.NetworkRepository
import com.personalization.sdk.domain.repositories.NotificationRepository
import com.personalization.utils.EnumUtils
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
-import javax.inject.Inject
class GetAllNotificationsUseCase @Inject constructor(
private val notificationRepository: NotificationRepository,
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/UpdateNotificationSourceUseCase.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/UpdateNotificationSourceUseCase.kt
index 4cf50d93..20d8bc40 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/UpdateNotificationSourceUseCase.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/notification/UpdateNotificationSourceUseCase.kt
@@ -11,7 +11,7 @@ class UpdateNotificationSourceUseCase @Inject constructor(
type: String,
id: String
) = notificationRepository.updateNotificationSource(
- type = type,
- id = id
- )
+ type = type,
+ id = id
+ )
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/recommendation/GetRecommendedByUseCase.kt b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/recommendation/GetRecommendedByUseCase.kt
index 0b5f4bea..f78c9d7f 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/recommendation/GetRecommendedByUseCase.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/sdk/domain/usecases/recommendation/GetRecommendedByUseCase.kt
@@ -8,7 +8,7 @@ class GetRecommendedByUseCase @Inject constructor(
private val recommendationRepository: RecommendationRepository
) {
- operator fun invoke() : RecommendedBy? {
+ operator fun invoke(): RecommendedBy? {
return recommendationRepository.getRecommendedBy()
}
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/Player.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/Player.kt
index 42dabd09..5d342cb4 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/Player.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/Player.kt
@@ -34,7 +34,9 @@ class Player(context: Context) {
val mediaSource = ProgressiveMediaSource.Factory(
CacheDataSource.Factory()
.setCache(cache!!)
- .setUpstreamDataSourceFactory(DefaultHttpDataSource.Factory().setUserAgent(SDK.userAgent()))
+ .setUpstreamDataSourceFactory(
+ DefaultHttpDataSource.Factory().setUserAgent(SDK.userAgent())
+ )
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
).createMediaSource(MediaItem.fromUri(url))
player.setMediaSource(mediaSource)
@@ -52,7 +54,7 @@ class Player(context: Context) {
}
companion object {
- var player: ExoPlayer? = null
+ var player: ExoPlayer? = null
private var cache: SimpleCache? = null
}
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/StoriesManager.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/StoriesManager.kt
index 41f6c8e2..52f21177 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/StoriesManager.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/StoriesManager.kt
@@ -5,14 +5,14 @@ import android.os.Looper
import android.util.Log
import com.personalization.SDK
import com.personalization.api.OnApiCallbackListener
-import com.personalization.sdk.domain.usecases.recommendation.SetRecommendedByUseCase
import com.personalization.sdk.domain.models.RecommendedBy
import com.personalization.sdk.domain.usecases.network.SendNetworkMethodUseCase
+import com.personalization.sdk.domain.usecases.recommendation.SetRecommendedByUseCase
import com.personalization.stories.models.Story
import com.personalization.stories.views.StoriesView
+import javax.inject.Inject
import org.json.JSONException
import org.json.JSONObject
-import javax.inject.Inject
class StoriesManager @Inject constructor(
val setRecommendedByUseCase: SetRecommendedByUseCase,
@@ -132,12 +132,12 @@ class StoriesManager @Inject constructor(
}
companion object {
- const val TRACK_STORIES_METHOD = "track/stories"
- const val REQUEST_STORIES_METHOD = "stories/%s"
+ const val TRACK_STORIES_METHOD = "track/stories"
+ const val REQUEST_STORIES_METHOD = "stories/%s"
- const val EVENT_PARAMS_NAME = "event"
- const val STORY_ID_PARAMS_NAME = "story_id"
- const val SLIDE_ID_PARAMS_NAME = "slide_id"
- const val CODE_PARAMS_NAME = "code"
+ const val EVENT_PARAMS_NAME = "event"
+ const val STORY_ID_PARAMS_NAME = "story_id"
+ const val SLIDE_ID_PARAMS_NAME = "slide_id"
+ const val CODE_PARAMS_NAME = "code"
}
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Slide.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Slide.kt
index cbf67eab..a8254f65 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Slide.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Slide.kt
@@ -6,9 +6,9 @@ import com.personalization.stories.models.elements.HeaderElement
import com.personalization.stories.models.elements.ProductElement
import com.personalization.stories.models.elements.ProductsElement
import com.personalization.stories.models.elements.TextBlockElement
-import org.json.JSONObject
import java.io.Serializable
import java.util.Objects
+import org.json.JSONObject
class Slide(json: JSONObject) : Serializable {
val id: String = json.optString("id", "")
@@ -40,17 +40,26 @@ class Slide(json: JSONObject) : Serializable {
if (this === other) return true
if (other !is Slide) return false
return duration == other.duration
- && isPrepared == other.isPrepared
- && id == other.id
- && background == other.background
- && backgroundColor == other.backgroundColor
- && preview == other.preview
- && type == other.type
- && elements == other.elements
+ && isPrepared == other.isPrepared
+ && id == other.id
+ && background == other.background
+ && backgroundColor == other.backgroundColor
+ && preview == other.preview
+ && type == other.type
+ && elements == other.elements
}
override fun hashCode(): Int {
- return Objects.hash(id, background, backgroundColor, preview, type, elements, duration, isPrepared)
+ return Objects.hash(
+ id,
+ background,
+ backgroundColor,
+ preview,
+ type,
+ elements,
+ duration,
+ isPrepared
+ )
}
override fun toString(): String {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Story.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Story.kt
index 61079904..1e2bab21 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Story.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/Story.kt
@@ -1,7 +1,7 @@
package com.personalization.stories.models
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class Story(json: JSONObject) {
val id: Int = json.optInt("id", 0)
@@ -32,12 +32,12 @@ class Story(json: JSONObject) {
if (this === other) return true
if (other !is Story) return false
return id == other.id
- && isViewed == other.isViewed
- && isPinned == other.isPinned
- && startPosition == other.startPosition
- && avatar == other.avatar
- && name == other.name
- && slides == other.slides
+ && isViewed == other.isViewed
+ && isPinned == other.isPinned
+ && startPosition == other.startPosition
+ && avatar == other.avatar
+ && name == other.name
+ && slides == other.slides
}
override fun hashCode(): Int {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ButtonElement.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ButtonElement.kt
index ce0cbdab..a4e4f4a2 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ButtonElement.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ButtonElement.kt
@@ -1,7 +1,7 @@
package com.personalization.stories.models.elements
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class ButtonElement(json: JSONObject) : LinkElement {
val title: String = json.optString("title", "")
@@ -14,10 +14,10 @@ class ButtonElement(json: JSONObject) : LinkElement {
if (this === other) return true
if (other !is ButtonElement) return false
return textBold == other.textBold
- && title == other.title
- && background == other.background
- && color == other.color
- && link == other.link
+ && title == other.title
+ && background == other.background
+ && color == other.color
+ && link == other.link
}
override fun hashCode(): Int {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/HeaderElement.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/HeaderElement.kt
index 62b576a9..4fe51150 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/HeaderElement.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/HeaderElement.kt
@@ -1,7 +1,7 @@
package com.personalization.stories.models.elements
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class HeaderElement(json: JSONObject) : LinkElement {
val title: String = json.optString("title", "")
@@ -13,9 +13,9 @@ class HeaderElement(json: JSONObject) : LinkElement {
if (this === other) return true
if (other !is HeaderElement) return false
return title == other.title
- && subtitle == other.subtitle
- && link == other.link
- && icon == other.icon
+ && subtitle == other.subtitle
+ && link == other.link
+ && icon == other.icon
}
override fun hashCode(): Int {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductElement.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductElement.kt
index f6d72a90..12d8fd6a 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductElement.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductElement.kt
@@ -1,8 +1,8 @@
package com.personalization.stories.models.elements
import com.personalization.Product
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class ProductElement(json: JSONObject) : Element {
val title: String = json.optString("title", "")
@@ -19,7 +19,7 @@ class ProductElement(json: JSONObject) : Element {
if (this === other) return true
if (other !is ProductElement) return false
return title == other.title
- && item == other.item
+ && item == other.item
}
override fun hashCode(): Int {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductsElement.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductsElement.kt
index b50cf8ad..672fe609 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductsElement.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/ProductsElement.kt
@@ -1,8 +1,8 @@
package com.personalization.stories.models.elements
import com.personalization.Product
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class ProductsElement(json: JSONObject) : Element {
var labelHide: String = ""
@@ -31,8 +31,8 @@ class ProductsElement(json: JSONObject) : Element {
if (this === other) return true
if (other !is ProductsElement) return false
return labelHide == other.labelHide
- && labelShow == other.labelShow
- && products == other.products
+ && labelShow == other.labelShow
+ && products == other.products
}
override fun hashCode(): Int {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/TextBlockElement.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/TextBlockElement.kt
index 0a67e0f5..21e5be2e 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/TextBlockElement.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/models/elements/TextBlockElement.kt
@@ -1,7 +1,7 @@
package com.personalization.stories.models.elements
-import org.json.JSONObject
import java.util.Objects
+import org.json.JSONObject
class TextBlockElement(json: JSONObject) : Element {
val isBold: Boolean = json.optBoolean("bold", false)
@@ -13,27 +13,41 @@ class TextBlockElement(json: JSONObject) : Element {
val textAlign: String = json.optString("text_align", "")
val textColor: String = json.optString("text_color", "")
val textLineSpacing: Double = json.optDouble("text_line_spacing", 0.0)
- val textBackgroundColor: String = json.optString("text_background_color", DEFAULT_TEXT_BACKGROUND_COLOR)
- val textBackgroundColorOpacity: String = json.optString("text_background_color_opacity", DEFAULT_TEXT_BACKGROUND_COLOR_OPACITY)
+ val textBackgroundColor: String =
+ json.optString("text_background_color", DEFAULT_TEXT_BACKGROUND_COLOR)
+ val textBackgroundColorOpacity: String =
+ json.optString("text_background_color_opacity", DEFAULT_TEXT_BACKGROUND_COLOR_OPACITY)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TextBlockElement) return false
return yOffset == other.yOffset
- && fontSize == other.fontSize
- && textLineSpacing.compareTo(other.textLineSpacing) == 0
- && isBold == other.isBold
- && isItalic == other.isItalic
- && textInput == other.textInput
- && fontType == other.fontType
- && textAlign == other.textAlign
- && textColor == other.textColor
- && textBackgroundColor == other.textBackgroundColor
- && textBackgroundColorOpacity == other.textBackgroundColorOpacity
+ && fontSize == other.fontSize
+ && textLineSpacing.compareTo(other.textLineSpacing) == 0
+ && isBold == other.isBold
+ && isItalic == other.isItalic
+ && textInput == other.textInput
+ && fontType == other.fontType
+ && textAlign == other.textAlign
+ && textColor == other.textColor
+ && textBackgroundColor == other.textBackgroundColor
+ && textBackgroundColorOpacity == other.textBackgroundColorOpacity
}
override fun hashCode(): Int {
- return Objects.hash(isBold, isItalic, textInput, yOffset, fontType, fontSize, textAlign, textColor, textLineSpacing, textBackgroundColor, textBackgroundColorOpacity)
+ return Objects.hash(
+ isBold,
+ isItalic,
+ textInput,
+ yOffset,
+ fontType,
+ fontSize,
+ textAlign,
+ textColor,
+ textLineSpacing,
+ textBackgroundColor,
+ textBackgroundColorOpacity
+ )
}
override fun toString(): String {
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/viewAdapters/StoriesAdapter.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/viewAdapters/StoriesAdapter.kt
index f338f4e7..2af85c8a 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/viewAdapters/StoriesAdapter.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/viewAdapters/StoriesAdapter.kt
@@ -18,7 +18,7 @@ import com.personalization.stories.Settings
import com.personalization.stories.models.Story
import com.personalization.stories.views.StoriesView
-class StoriesAdapter (
+class StoriesAdapter(
private val storiesView: StoriesView,
private val data: List,
private val listener: ClickListener
@@ -59,7 +59,8 @@ class StoriesAdapter (
Glide.with(image.context).load(firstSlide.background).preload()
}
if (storiesView.settings.new_campaign_border_color != null) {
- border.strokeWidth = border.context.resources.getDimension(R.dimen.story_avatar_border)
+ border.strokeWidth =
+ border.context.resources.getDimension(R.dimen.story_avatar_border)
border.strokeColor = ColorStateList.valueOf(
Color.parseColor(
if (story.isViewed) settings.visited_campaign_border_color
@@ -68,7 +69,8 @@ class StoriesAdapter (
)
} else {
//Default border style for old api
- border.strokeWidth = if (story.isViewed) 0f else border.context.resources.getDimension(R.dimen.story_avatar_border)
+ border.strokeWidth =
+ if (story.isViewed) 0f else border.context.resources.getDimension(R.dimen.story_avatar_border)
}
itemView.alpha = if (story.isViewed) settings.visited_campaign_transparency else 1f
@@ -90,13 +92,16 @@ class StoriesAdapter (
name.setTextColor(Color.parseColor(settings.label_font_color))
name.textSize = settings.label_font_size.toFloat()
name.typeface = settings.label_font_family
- name.width = ((if (settings.label_width != null) settings.label_width!! else settings.icon_size) * scale).toInt()
+ name.width =
+ ((if (settings.label_width != null) settings.label_width!! else settings.icon_size) * scale).toInt()
pin.visibility = if (story.isPinned) View.VISIBLE else View.GONE
pin.text = settings.pin_symbol
- val shapeAppearanceModel = ShapeAppearanceModel().toBuilder().setAllCorners(CornerFamily.ROUNDED, 50f).build()
+ val shapeAppearanceModel =
+ ShapeAppearanceModel().toBuilder().setAllCorners(CornerFamily.ROUNDED, 50f).build()
val shapeDrawable = MaterialShapeDrawable(shapeAppearanceModel)
- shapeDrawable.fillColor = ColorStateList.valueOf(Color.parseColor(settings.background_pin))
+ shapeDrawable.fillColor =
+ ColorStateList.valueOf(Color.parseColor(settings.background_pin))
ViewCompat.setBackground(pin, shapeDrawable)
}
@@ -106,7 +111,8 @@ class StoriesAdapter (
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
- val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.story_avatar, viewGroup, false)
+ val view =
+ LayoutInflater.from(viewGroup.context).inflate(R.layout.story_avatar, viewGroup, false)
return ViewHolder(view, listener)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PausableProgressBar.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PausableProgressBar.kt
index 3e0fe17a..421b300b 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PausableProgressBar.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PausableProgressBar.kt
@@ -91,7 +91,16 @@ internal class PausableProgressBar @JvmOverloads constructor(
fun startProgress() {
maxProgressView.visibility = GONE
- animation = PausableScaleAnimation(0f, 1f, 1f, 1f, Animation.ABSOLUTE, 0f, Animation.RELATIVE_TO_SELF, 0f)
+ animation = PausableScaleAnimation(
+ 0f,
+ 1f,
+ 1f,
+ 1f,
+ Animation.ABSOLUTE,
+ 0f,
+ Animation.RELATIVE_TO_SELF,
+ 0f
+ )
animation?.let { animation ->
animation.duration = duration
animation.interpolator = LinearInterpolator()
@@ -133,13 +142,18 @@ internal class PausableProgressBar @JvmOverloads constructor(
animation = null
}
- class PausableScaleAnimation internal constructor(fromX: Float, toX: Float, fromY: Float,
+ class PausableScaleAnimation internal constructor(
+ fromX: Float, toX: Float, fromY: Float,
toY: Float, pivotXType: Int, pivotXValue: Float, pivotYType: Int, pivotYValue: Float
) : ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue) {
private var mElapsedAtPause: Long = 0
private var mPaused = false
- override fun getTransformation(currentTime: Long, outTransformation: Transformation, scale: Float): Boolean {
+ override fun getTransformation(
+ currentTime: Long,
+ outTransformation: Transformation,
+ scale: Float
+ ): Boolean {
if (mPaused && mElapsedAtPause == 0L) {
mElapsedAtPause = currentTime - startTime
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PullDismissLayout.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PullDismissLayout.kt
index 9e3be1e7..380b1dec 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PullDismissLayout.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/PullDismissLayout.kt
@@ -30,7 +30,11 @@ internal class PullDismissLayout : FrameLayout {
init(context)
}
- constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
+ constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
+ context,
+ attrs,
+ defStyle
+ ) {
init(context)
}
@@ -85,7 +89,8 @@ internal class PullDismissLayout : FrameLayout {
}
if (!dragHelper.shouldInterceptTouchEvent(event) && pullingDown) {
if (dragHelper.viewDragState == ViewDragHelper.STATE_IDLE
- && dragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL)) {
+ && dragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL)
+ ) {
val child = getChildAt(0)
if (child != null && listener?.onShouldInterceptTouchEvent() != true) {
dragHelper.captureChildView(child, event.getPointerId(0))
@@ -108,7 +113,8 @@ internal class PullDismissLayout : FrameLayout {
return false
}
- private class ViewDragCallback(private val pullDismissLayout: PullDismissLayout) : ViewDragHelper.Callback() {
+ private class ViewDragCallback(private val pullDismissLayout: PullDismissLayout) :
+ ViewDragHelper.Callback() {
private var startTop = 0
private var dragPercent = 0.0f
private var capturedView: View? = null
@@ -151,7 +157,7 @@ internal class PullDismissLayout : FrameLayout {
override fun onViewReleased(view: View, xv: Float, yv: Float) {
dismissed = dragPercent >= 0.50f
- || (abs(xv.toDouble()) > pullDismissLayout.minFlingVelocity && dragPercent > 0.20f)
+ || (abs(xv.toDouble()) > pullDismissLayout.minFlingVelocity && dragPercent > 0.20f)
val finalTop = if (dismissed) pullDismissLayout.height else startTop
if (!dismissed) {
pullDismissLayout.listener?.onReleased()
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesProgressView.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesProgressView.kt
index de63da6d..1dcf855c 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesProgressView.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesProgressView.kt
@@ -42,13 +42,13 @@ internal class StoriesProgressView : LinearLayout {
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
- : super(context, attrs, defStyleAttr) {
+ : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int)
- : super(context, attrs, defStyleAttr, defStyleRes) {
+ : super(context, attrs, defStyleAttr, defStyleRes) {
init(context, attrs)
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesView.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesView.kt
index 793821af..c7529207 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesView.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/StoriesView.kt
@@ -90,7 +90,8 @@ class StoriesView : ConstraintLayout, ClickListener {
private fun parseAttrs(attrs: AttributeSet?) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.StoriesView)
val code = typedArray.getString(R.styleable.StoriesView_code)
- val openingWebView = typedArray.getBoolean(R.styleable.StoriesView_need_opening_web_view, true)
+ val openingWebView =
+ typedArray.getBoolean(R.styleable.StoriesView_need_opening_web_view, true)
if (code == null) {
SDK.error("Code is set incorrectly")
return
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/storyItem/TextBlockView.kt b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/storyItem/TextBlockView.kt
index 3ad02d5a..da8bde18 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/stories/views/storyItem/TextBlockView.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/stories/views/storyItem/TextBlockView.kt
@@ -14,7 +14,10 @@ class TextBlockView(context: Context) : AppCompatTextView(context) {
@SuppressLint("ResourceAsColor")
fun updateView(element: TextBlockElement, parentHeight: Int, parentTopOffset: Int) {
- val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ val layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT
+ )
setLayoutParams(layoutParams)
text = element.textInput
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/ColorUtils.kt b/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/ColorUtils.kt
index 1919f536..16a1a66f 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/ColorUtils.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/ColorUtils.kt
@@ -23,7 +23,8 @@ object ColorUtils {
if (percentsString.isNotEmpty()) {
percents = percentsString.substring(0, percentsString.length - 1).toInt()
}
- } catch (ignored: NumberFormatException) {}
+ } catch (ignored: NumberFormatException) {
+ }
}
return MAX_COLOR_CHANNEL_VALUE * percents / 100
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/TextUtils.kt b/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/TextUtils.kt
index 63d7be9c..bccf0720 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/TextUtils.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/ui/utils/TextUtils.kt
@@ -39,9 +39,11 @@ object TextUtils {
else -> R.font.droid_serif_regular
}
}
+
"sans-serif" -> {
if (bold) R.font.droid_sans_bold else R.font.droid_sans_regular
}
+
"monospaced" -> R.font.droid_sans_mono
else -> R.font.droid_sans_mono
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/utils/EnumUtils.kt b/personalization-sdk/src/main/kotlin/com/personalization/utils/EnumUtils.kt
index 18296f2c..e11c7709 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/utils/EnumUtils.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/utils/EnumUtils.kt
@@ -8,7 +8,7 @@ object EnumUtils {
return enums.joinToString(",") { it.toString() }
}
- infix fun> EnumSet.and(other: T): EnumSet {
+ infix fun > EnumSet.and(other: T): EnumSet {
this.add(other)
return this
}
diff --git a/personalization-sdk/src/main/kotlin/com/personalization/utils/TimeUtils.kt b/personalization-sdk/src/main/kotlin/com/personalization/utils/TimeUtils.kt
index 7de7bf2e..b4790a2c 100644
--- a/personalization-sdk/src/main/kotlin/com/personalization/utils/TimeUtils.kt
+++ b/personalization-sdk/src/main/kotlin/com/personalization/utils/TimeUtils.kt
@@ -3,7 +3,7 @@ package com.personalization.utils
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
-object TimeUtils {
+object TimeUtils {
val TWO_DAYS: Duration = 2.days
}
diff --git a/personalization-sdk/src/main/res/drawable/app_icon.xml b/personalization-sdk/src/main/res/drawable/app_icon.xml
new file mode 100644
index 00000000..af981f80
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/app_icon.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/personalization-sdk/src/main/res/drawable/ic_arrow_close.xml b/personalization-sdk/src/main/res/drawable/ic_arrow_close.xml
new file mode 100644
index 00000000..29084ed4
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/ic_arrow_close.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/personalization-sdk/src/main/res/drawable/ic_arrow_open.xml b/personalization-sdk/src/main/res/drawable/ic_arrow_open.xml
new file mode 100644
index 00000000..1107e820
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/ic_arrow_open.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/personalization-sdk/src/main/res/drawable/ic_notification_logo.xml b/personalization-sdk/src/main/res/drawable/ic_notification_logo.xml
new file mode 100644
index 00000000..b15c90c7
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/ic_notification_logo.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/personalization-sdk/src/main/res/drawable/ic_product_image.xml b/personalization-sdk/src/main/res/drawable/ic_product_image.xml
index 9980eac1..0a4f444c 100644
--- a/personalization-sdk/src/main/res/drawable/ic_product_image.xml
+++ b/personalization-sdk/src/main/res/drawable/ic_product_image.xml
@@ -3,18 +3,17 @@
android:height="512dp"
android:viewportWidth="512"
android:viewportHeight="512">
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/personalization-sdk/src/main/res/drawable/image_error.png b/personalization-sdk/src/main/res/drawable/image_error.png
new file mode 100644
index 00000000..4e883c6c
Binary files /dev/null and b/personalization-sdk/src/main/res/drawable/image_error.png differ
diff --git a/personalization-sdk/src/main/res/drawable/image_rounded_borders.xml b/personalization-sdk/src/main/res/drawable/image_rounded_borders.xml
new file mode 100644
index 00000000..150a8c39
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/image_rounded_borders.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/drawable/notification_roudned_background.xml b/personalization-sdk/src/main/res/drawable/notification_roudned_background.xml
new file mode 100644
index 00000000..fb9970bd
--- /dev/null
+++ b/personalization-sdk/src/main/res/drawable/notification_roudned_background.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/drawable/rounded_button_background.xml b/personalization-sdk/src/main/res/drawable/rounded_button_background.xml
index d8b14b99..108a1a03 100644
--- a/personalization-sdk/src/main/res/drawable/rounded_button_background.xml
+++ b/personalization-sdk/src/main/res/drawable/rounded_button_background.xml
@@ -1,9 +1,11 @@
-
-
+
+
+ android:topRightRadius="10dp" />
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/drawable/story_description_background.xml b/personalization-sdk/src/main/res/drawable/story_description_background.xml
index 46445d4d..34a4bc5c 100644
--- a/personalization-sdk/src/main/res/drawable/story_description_background.xml
+++ b/personalization-sdk/src/main/res/drawable/story_description_background.xml
@@ -81,7 +81,9 @@
android:right="32dp"
android:top="8dp" />
-
+
diff --git a/personalization-sdk/src/main/res/layout/custom_notification.xml b/personalization-sdk/src/main/res/layout/custom_notification.xml
new file mode 100644
index 00000000..17a558b9
--- /dev/null
+++ b/personalization-sdk/src/main/res/layout/custom_notification.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/layout/dialog_stories.xml b/personalization-sdk/src/main/res/layout/dialog_stories.xml
index 9000d09b..f0d50ad8 100644
--- a/personalization-sdk/src/main/res/layout/dialog_stories.xml
+++ b/personalization-sdk/src/main/res/layout/dialog_stories.xml
@@ -1,7 +1,6 @@
diff --git a/personalization-sdk/src/main/res/layout/notification_progress_container.xml b/personalization-sdk/src/main/res/layout/notification_progress_container.xml
new file mode 100644
index 00000000..cec07103
--- /dev/null
+++ b/personalization-sdk/src/main/res/layout/notification_progress_container.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/layout/pausable_progress.xml b/personalization-sdk/src/main/res/layout/pausable_progress.xml
index 86dfb18d..ae75b017 100644
--- a/personalization-sdk/src/main/res/layout/pausable_progress.xml
+++ b/personalization-sdk/src/main/res/layout/pausable_progress.xml
@@ -16,7 +16,7 @@
android:layout_height="@dimen/progress_bar_height"
android:background="@color/progress_primary"
android:visibility="invisible"
- tools:visibility="visible"/>
+ tools:visibility="visible" />
+
-
+ android:layout_marginEnd="16dp">
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dp" />
diff --git a/personalization-sdk/src/main/res/values-ru/strings.xml b/personalization-sdk/src/main/res/values-ru/strings.xml
index 4462f340..9b02b0f1 100644
--- a/personalization-sdk/src/main/res/values-ru/strings.xml
+++ b/personalization-sdk/src/main/res/values-ru/strings.xml
@@ -3,11 +3,14 @@
Не удалось загрузить данные. Проверьте подключение и повторите попытку.
Вперёд
Назад
+ Повторить
Accept
Cancel
Pizza ipsum dolor meat lovers buffalo.
Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Error loading images.
+ Invalid notification data.
\ No newline at end of file
diff --git a/personalization-sdk/src/main/res/values/colors.xml b/personalization-sdk/src/main/res/values/colors.xml
index 26928ab6..407e83ed 100644
--- a/personalization-sdk/src/main/res/values/colors.xml
+++ b/personalization-sdk/src/main/res/values/colors.xml
@@ -1,12 +1,13 @@
- #3F51B5
- #303F9F
- #FF4081
- #000000
- #808080
- #FF0000
- #00FF00
- #FFFFFF
- #3B82F6
+ #3F51B5
+ #303F9F
+ #FF4081
+ #000000
+ #808080
+ #FF0000
+ #00FF00
+ #FFFFFF
+ #3B82F6
+ #262626
diff --git a/personalization-sdk/src/main/res/values/strings.xml b/personalization-sdk/src/main/res/values/strings.xml
index 5f9b1bd7..81778c9e 100644
--- a/personalization-sdk/src/main/res/values/strings.xml
+++ b/personalization-sdk/src/main/res/values/strings.xml
@@ -1,25 +1,28 @@
- notification_channel
- notification_channel
+ notification_channel
+ notification_channel
-
-
-
-
+
+
+
+
- 32dp
- 8dp
- #F97316
- #17AADF
+ 32dp
+ 8dp
+ #F97316
+ #17AADF
- Failed to retrieve data. Please check your connection and try again.
- Previous
- Next
+ Failed to retrieve data. Please check your connection and try again.
+ Previous
+ Next
+ Retry
- Accept
- Cancel
- Pizza ipsum dolor meat lovers buffalo.
- Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
- Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Accept
+ Cancel
+ Pizza ipsum dolor meat lovers buffalo.
+ Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
+ Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Error loading images.
+ Invalid notification data.
diff --git a/personalization-sdk/src/personaclick/kotlin/com/personaclick/sdk/Personaclick.kt b/personalization-sdk/src/personaclick/kotlin/com/personaclick/sdk/Personaclick.kt
index 33e3813e..a753d1ea 100644
--- a/personalization-sdk/src/personaclick/kotlin/com/personaclick/sdk/Personaclick.kt
+++ b/personalization-sdk/src/personaclick/kotlin/com/personaclick/sdk/Personaclick.kt
@@ -17,7 +17,7 @@ class Personaclick private constructor() : SDK() {
private const val NOTIFICATION_TYPE: String = "PERSONACLICK_NOTIFICATION_TYPE"
private const val NOTIFICATION_ID: String = "PERSONACLICK_NOTIFICATION_ID"
- fun getInstance() : SDK = instance
+ fun getInstance(): SDK = instance
/**
* Initialize api
@@ -41,7 +41,7 @@ class Personaclick private constructor() : SDK() {
preferencesKey = PREFERENCES_KEY,
stream = PLATFORM_ANDROID,
notificationType = NOTIFICATION_TYPE,
- notificationId = NOTIFICATION_ID,
+ notificationId = NOTIFICATION_ID,
autoSendPushToken = autoSendPushToken
)
}
diff --git a/personalization-sdk/src/rees46/kotlin/com/rees46/sdk/REES46.kt b/personalization-sdk/src/rees46/kotlin/com/rees46/sdk/REES46.kt
index 49535b47..b0ee31e5 100644
--- a/personalization-sdk/src/rees46/kotlin/com/rees46/sdk/REES46.kt
+++ b/personalization-sdk/src/rees46/kotlin/com/rees46/sdk/REES46.kt
@@ -1,11 +1,10 @@
package com.rees46.sdk
import android.content.Context
-import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager
import com.personalization.BuildConfig
import com.personalization.SDK
-import com.personalization.notification.NotificationHelper
+import com.personalization.features.notification.domain.model.NotificationData
+import com.personalization.features.notification.presentation.helpers.NotificationImageHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -61,16 +60,20 @@ class REES46 private constructor() : SDK() {
autoSendPushToken = autoSendPushToken
)
- sdk.setOnMessageListener { data: Map ->
+ sdk.setOnMessageListener { data ->
coroutineScope.launch {
- val images = withContext(Dispatchers.IO) {
- NotificationHelper.loadBitmaps(urls = data[NotificationHelper.NOTIFICATION_IMAGES])
+ val (images, hasError) = withContext(Dispatchers.IO) {
+ NotificationImageHelper.loadBitmaps(urls = data.images)
}
- NotificationHelper.createNotification(
+ sdk.notificationHelper.createNotification(
context = context,
- data = data,
+ data = NotificationData(
+ title = data.title,
+ body = data.body,
+ images = data.images
+ ),
images = images,
- currentIndex = 0
+ hasError = hasError
)
}
}
diff --git a/sample/build.gradle b/sample/build.gradle
index 49f6ecc0..60402717 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -1,70 +1,70 @@
plugins {
- id 'com.android.application'
- id 'com.google.gms.google-services'
- id 'org.jetbrains.kotlin.android'
+ id 'com.android.application'
+ id 'com.google.gms.google-services'
+ id 'org.jetbrains.kotlin.android'
}
android {
- namespace 'com.personalization.sample'
+ namespace 'com.personalization.sample'
- signingConfigs {
- release {
- storeFile file('../test.key')
- storePassword '123456'
- keyAlias 'test'
- keyPassword '123456'
- }
- }
- compileSdk 34
- flavorDimensions += 'default'
- defaultConfig {
- minSdkVersion 19
- multiDexEnabled true
- applicationId 'com.personalization.sample'
- targetSdkVersion 34
- versionCode 1
- versionName "1.0"
- }
- buildTypes {
- debug {
+ signingConfigs {
+ release {
+ storeFile file('../test.key')
+ storePassword '123456'
+ keyAlias 'test'
+ keyPassword '123456'
+ }
+ }
+ compileSdk 34
+ flavorDimensions += 'default'
+ defaultConfig {
+ minSdkVersion 19
+ multiDexEnabled true
+ applicationId 'com.personalization.sample'
+ targetSdkVersion 34
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ debug {
- }
- release {
- minifyEnabled false
- debuggable true
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- signingConfig signingConfigs.release
- }
- }
- productFlavors {
- rees46 {
- applicationId = 'com.rees46.sample'
- }
- personaclick {
- applicationId = 'com.personaclick.sample'
- }
- }
+ }
+ release {
+ minifyEnabled false
+ debuggable true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.release
+ }
+ }
+ productFlavors {
+ rees46 {
+ applicationId = 'com.rees46.sample'
+ }
+ personaclick {
+ applicationId = 'com.personaclick.sample'
+ }
+ }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_20
- targetCompatibility JavaVersion.VERSION_20
- }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_20
+ targetCompatibility JavaVersion.VERSION_20
+ }
- kotlinOptions {
- jvmTarget = '20'
- }
+ kotlinOptions {
+ jvmTarget = '20'
+ }
}
configurations {
- rees46DebugImplementation
- personaclickDebugImplementation
+ rees46DebugImplementation
+ personaclickDebugImplementation
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation 'androidx.recyclerview:recyclerview:1.3.2'
- implementation project(path: ':personalization-sdk')
- implementation 'androidx.core:core-ktx:1.13.1'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.recyclerview:recyclerview:1.3.2'
+ implementation project(path: ':personalization-sdk')
+ implementation 'androidx.core:core-ktx:1.13.1'
}
diff --git a/sample/src/main/kotlin/com/personalization/sample/AbstractMainActivity.kt b/sample/src/main/kotlin/com/personalization/sample/AbstractMainActivity.kt
index 3348b723..cd1646a8 100644
--- a/sample/src/main/kotlin/com/personalization/sample/AbstractMainActivity.kt
+++ b/sample/src/main/kotlin/com/personalization/sample/AbstractMainActivity.kt
@@ -17,7 +17,15 @@ import androidx.core.content.ContextCompat
import com.personalization.OnClickListener
import com.personalization.Product
import com.personalization.SDK
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_BODY
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_IMAGES
+import com.personalization.features.notification.domain.model.NotificationConstants.NOTIFICATION_TITLE
+import com.personalization.features.notification.domain.model.NotificationData
+import com.personalization.features.notification.presentation.helpers.NotificationImageHelper.loadBitmaps
import com.personalization.stories.views.StoriesView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
abstract class AbstractMainActivity internal constructor(
private val sdk: SDK
@@ -36,6 +44,7 @@ abstract class AbstractMainActivity internal constructor(
initializingFragmentManager()
initializingStoriesView()
handleInAppNotifications()
+ handlePushNotification()
}
private fun handlePermissions() {
@@ -177,4 +186,29 @@ abstract class AbstractMainActivity internal constructor(
)
}
}
+
+ private fun handlePushNotification() {
+ findViewById
\ No newline at end of file
diff --git a/sample/src/main/res/layout/notification_slider_image.xml b/sample/src/main/res/layout/notification_slider_image.xml
index 8d3f63c8..545b57da 100644
--- a/sample/src/main/res/layout/notification_slider_image.xml
+++ b/sample/src/main/res/layout/notification_slider_image.xml
@@ -1,7 +1,6 @@
-
\ No newline at end of file
+ android:layout_height="200dp" />
\ No newline at end of file
diff --git a/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index db69e7e1..eca70cfe 100644
--- a/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index db69e7e1..eca70cfe 100644
--- a/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/values-ru/strings.xml b/sample/src/main/res/values-ru/strings.xml
index 8bd5200d..ccd5de95 100644
--- a/sample/src/main/res/values-ru/strings.xml
+++ b/sample/src/main/res/values-ru/strings.xml
@@ -7,5 +7,7 @@
Pizza ipsum dolor meat lovers buffalo.
Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Error loading images.
+ Invalid notification data.
\ No newline at end of file
diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml
index 26928ab6..ef4b4c7a 100644
--- a/sample/src/main/res/values/colors.xml
+++ b/sample/src/main/res/values/colors.xml
@@ -1,12 +1,12 @@
- #3F51B5
- #303F9F
- #FF4081
- #000000
- #808080
- #FF0000
- #00FF00
- #FFFFFF
- #3B82F6
+ #3F51B5
+ #303F9F
+ #FF4081
+ #000000
+ #808080
+ #FF0000
+ #00FF00
+ #FFFFFF
+ #3B82F6
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
index c1783fcd..6b1bcc75 100644
--- a/sample/src/main/res/values/strings.xml
+++ b/sample/src/main/res/values/strings.xml
@@ -1,10 +1,12 @@
- Personalizatio SDK Sample
+ Personalizatio SDK Sample
- Accept
- Cancel
- Pizza ipsum dolor meat lovers buffalo.
- Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
- Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Accept
+ Cancel
+ Pizza ipsum dolor meat lovers buffalo.
+ Pizza ipsum dolor meat lovers buffalo. Cheese ranch Philly red marinara ricotta lovers steak NY beef.
+ Pizza ipsum dolor meat lovers buffalo. Garlic sauce party sautéed ipsum cheese. Meatball mayo extra peppers Chicago spinach olives. Philly black crust pineapple steak ranch large large. Chicken hand pie tossed pan mushrooms large Bianca deep. Mozzarella roll string party mouth style lovers Hawaiian pan. Ricotta mayo red pizza fresh style string string. Broccoli meatball wing cheese sautéed. Peppers ipsum Aussie cheese olives Philly Hawaiian Aussie cheese personal. Pork dolor sausage bell mozzarella pepperoni thin deep mushrooms.
+ Error loading images.
+ Invalid notification data.
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
index 79a66e27..5885930d 100644
--- a/sample/src/main/res/values/styles.xml
+++ b/sample/src/main/res/values/styles.xml
@@ -1,11 +1,11 @@
-
-
+
+
diff --git a/sample/src/personaclick/AndroidManifest.xml b/sample/src/personaclick/AndroidManifest.xml
index 8d8a0808..0a521fe0 100644
--- a/sample/src/personaclick/AndroidManifest.xml
+++ b/sample/src/personaclick/AndroidManifest.xml
@@ -14,7 +14,8 @@
tools:replace="android:name"
tools:ignore="GoogleAppIndexingWarning">
-
diff --git a/sample/src/rees46/AndroidManifest.xml b/sample/src/rees46/AndroidManifest.xml
index 108e23ee..70be7cad 100644
--- a/sample/src/rees46/AndroidManifest.xml
+++ b/sample/src/rees46/AndroidManifest.xml
@@ -15,7 +15,9 @@
tools:ignore="GoogleAppIndexingWarning"
tools:targetApi="m">
-
+
diff --git a/sample/src/rees46/res/drawable/ic_base_notification.png b/sample/src/rees46/res/drawable/ic_base_notification.png
new file mode 100644
index 00000000..7eb2a0e6
Binary files /dev/null and b/sample/src/rees46/res/drawable/ic_base_notification.png differ
diff --git a/sample/src/rees46/res/values/colors.xml b/sample/src/rees46/res/values/colors.xml
index 804aac0f..b6e70d8e 100644
--- a/sample/src/rees46/res/values/colors.xml
+++ b/sample/src/rees46/res/values/colors.xml
@@ -1,11 +1,11 @@
- #3F51B5
- #303F9F
- #FF4081
- #000000
- #808080
- #FF0000
- #00FF00
- #FFFFFF
+ #3F51B5
+ #303F9F
+ #FF4081
+ #000000
+ #808080
+ #FF0000
+ #00FF00
+ #FFFFFF