Skip to content

Commit 0a1069d

Browse files
authored
Merge pull request #273 from mindbox-moscow/release-2.2.1
Release 2.2.1
2 parents 7adc30d + a6a641b commit 0a1069d

File tree

10 files changed

+190
-61
lines changed

10 files changed

+190
-61
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ android.enableJetifier=true
2121
kotlin.code.style=official
2222

2323
# SDK version property
24-
SDK_VERSION_NAME=2.2.0
24+
SDK_VERSION_NAME=2.2.1

sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ object Mindbox {
8989

9090
private val mutex = Mutex()
9191

92+
private var diInitialized: Boolean = false
93+
9294
/**
9395
* Allows you to specify additional components for message handling
9496
* when calling the [handleRemoteMessage] function.
@@ -354,8 +356,11 @@ object Mindbox {
354356
) {
355357
LoggingExceptionHandler.runCatching {
356358
initComponents(context, pushServices)
357-
startKoin {
358-
modules(appModule, dataModule)
359+
if (!diInitialized) {
360+
startKoin {
361+
modules(appModule, dataModule)
362+
}
363+
diInitialized = true
359364
}
360365
initScope.launch {
361366
val checkResult = checkConfig(configuration)

sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/data/InAppRepositoryImpl.kt

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
package cloud.mindbox.mobile_sdk.inapp.data
22

33
import android.content.Context
4+
import cloud.mindbox.mobile_sdk.Mindbox
45
import cloud.mindbox.mobile_sdk.MindboxConfiguration
56
import cloud.mindbox.mobile_sdk.inapp.domain.InAppRepository
67
import cloud.mindbox.mobile_sdk.inapp.mapper.InAppMessageMapper
8+
import cloud.mindbox.mobile_sdk.inapp.presentation.InAppMessageManager
9+
import cloud.mindbox.mobile_sdk.logger.MindboxLogger
10+
import cloud.mindbox.mobile_sdk.logger.MindboxLoggerImpl
711
import cloud.mindbox.mobile_sdk.managers.GatewayManager
812
import cloud.mindbox.mobile_sdk.managers.MindboxEventManager
913
import cloud.mindbox.mobile_sdk.models.InAppConfig
1014
import cloud.mindbox.mobile_sdk.models.InAppEventType
1115
import cloud.mindbox.mobile_sdk.models.SegmentationCheckInApp
1216
import cloud.mindbox.mobile_sdk.models.operation.request.InAppHandleRequest
17+
import cloud.mindbox.mobile_sdk.models.operation.response.FormDto
1318
import cloud.mindbox.mobile_sdk.models.operation.response.InAppConfigResponse
19+
import cloud.mindbox.mobile_sdk.models.operation.response.InAppConfigResponseBlank
1420
import cloud.mindbox.mobile_sdk.models.operation.response.PayloadDto
1521
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
1622
import cloud.mindbox.mobile_sdk.utils.LoggingExceptionHandler
1723
import cloud.mindbox.mobile_sdk.utils.RuntimeTypeAdapterFactory
1824
import com.google.gson.Gson
1925
import com.google.gson.GsonBuilder
26+
import com.google.gson.JsonObject
2027
import com.google.gson.reflect.TypeToken
2128
import kotlinx.coroutines.flow.Flow
2229
import kotlinx.coroutines.flow.map
@@ -80,19 +87,77 @@ internal class InAppRepositoryImpl : InAppRepository {
8087
gson.toJson(shownInApps, object : TypeToken<HashSet<String>>() {}.type)
8188
}
8289

83-
override fun listenInAppConfig(): Flow<InAppConfig> {
84-
return MindboxPreferences.inAppConfigFlow.map { inAppConfig ->
85-
inAppMapper.mapInAppConfigResponseToInAppConfig(
86-
GsonBuilder().registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(
87-
PayloadDto::class.java,
88-
TYPE_JSON_NAME)
89-
.registerSubtype(PayloadDto.SimpleImage::class.java,
90-
SIMPLE_IMAGE_JSON_NAME))
91-
.create()
92-
.fromJson(inAppConfig,
93-
InAppConfigResponse::class.java)
90+
override fun listenInAppConfig(): Flow<InAppConfig?> {
91+
return MindboxPreferences.inAppConfigFlow.map { inAppConfigString ->
92+
MindboxLoggerImpl.d(
93+
parent = this@InAppRepositoryImpl,
94+
message = "CachedConfig : $inAppConfigString"
9495
)
96+
val configBlank = deserializeToConfigDtoBlank(inAppConfigString)
97+
val filteredInApps = configBlank?.inApps
98+
?.filter { validateInAppVersion(it) }
99+
?.map { inAppDtoBlank ->
100+
inAppMapper.mapToInAppDto(
101+
inAppDtoBlank = inAppDtoBlank,
102+
formDto = deserializeToInAppFormDto(inAppDtoBlank.form),
103+
)
104+
}
105+
val filteredConfig = InAppConfigResponse(
106+
inApps = filteredInApps
107+
)
108+
return@map inAppMapper.mapInAppConfigResponseToInAppConfig(filteredConfig).also { inAppConfig ->
109+
MindboxLoggerImpl.d(
110+
parent = this@InAppRepositoryImpl,
111+
message = "Providing config: $inAppConfig"
112+
)
113+
}
114+
}
115+
}
116+
117+
private fun deserializeToConfigDtoBlank(inAppConfig: String): InAppConfigResponseBlank? {
118+
val result = runCatching {
119+
gson.fromJson(inAppConfig, InAppConfigResponseBlank::class.java)
95120
}
121+
result.exceptionOrNull()?.let { error ->
122+
MindboxLoggerImpl.e(
123+
parent = this@InAppRepositoryImpl,
124+
message = "Failed to parse inAppConfig: $inAppConfig",
125+
exception = error
126+
)
127+
}
128+
return result.getOrNull()
129+
}
130+
131+
private fun deserializeToInAppFormDto(inAppForm: JsonObject?): FormDto? {
132+
val result = runCatching {
133+
GsonBuilder().registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(
134+
PayloadDto::class.java,
135+
TYPE_JSON_NAME)
136+
.registerSubtype(PayloadDto.SimpleImage::class.java,
137+
SIMPLE_IMAGE_JSON_NAME))
138+
.create()
139+
.fromJson(inAppForm,
140+
FormDto::class.java)
141+
}
142+
result.exceptionOrNull()?.let { error ->
143+
MindboxLoggerImpl.e(
144+
parent = this@InAppRepositoryImpl,
145+
message = "Failed to parse JsonObject: $inAppForm",
146+
exception = error
147+
)
148+
}
149+
return result.getOrNull()
150+
}
151+
152+
private fun validateInAppVersion(inAppDto: InAppConfigResponseBlank.InAppDtoBlank): Boolean {
153+
val sdkVersion = inAppDto.sdkVersion ?: return false
154+
val minVersionValid = sdkVersion.minVersion?.let { min ->
155+
min <= InAppMessageManager.CURRENT_IN_APP_VERSION
156+
} ?: true
157+
val maxVersionValid = sdkVersion.maxVersion?.let { max ->
158+
max >= InAppMessageManager.CURRENT_IN_APP_VERSION
159+
} ?: true
160+
return minVersionValid && maxVersionValid
96161
}
97162

98163
companion object {

sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppInteractor.kt

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,24 @@ internal class InAppInteractor {
2323
configuration: MindboxConfiguration,
2424
): Flow<InAppType> {
2525
return inAppRepositoryImpl.listenInAppConfig()
26+
.filterNotNull()
2627
//TODO add eventProcessing
2728
.combine(inAppRepositoryImpl.listenInAppEvents()
28-
.filter { inAppEventType -> inAppEventType is InAppEventType.AppStartup }) { config, event ->
29+
.filter { inAppEventType ->
30+
MindboxLoggerImpl.d(this, "Event triggered: $inAppEventType")
31+
inAppEventType is InAppEventType.AppStartup
32+
}) { config, event ->
2933
val filteredConfig = prefilterConfig(config)
34+
MindboxLoggerImpl.d(this,
35+
"Filtered config has ${filteredConfig.inApps.size} inapps")
3036
val filteredConfigWithTargeting = getConfigWithTargeting(filteredConfig)
3137
val inAppsWithoutTargeting =
3238
filteredConfig.inApps.subtract(filteredConfigWithTargeting.inApps.toSet())
3339
val inApp = if (inAppsWithoutTargeting.isNotEmpty()) {
34-
inAppsWithoutTargeting.first()
40+
inAppsWithoutTargeting.first().also {
41+
MindboxLoggerImpl.d(this,
42+
"Inapp without targeting found: ${it.id}")
43+
}
3544
} else if (filteredConfigWithTargeting.inApps.isNotEmpty()) {
3645
runCatching {
3746
checkSegmentation(filteredConfig,
@@ -50,19 +59,26 @@ internal class InAppInteractor {
5059
null
5160
}
5261

53-
when (val type = inApp?.form?.variants?.first()) {
62+
when (val type = inApp?.form?.variants?.firstOrNull()) {
5463
is Payload.SimpleImage -> InAppType.SimpleImage(inAppId = inApp.id,
5564
imageUrl = type.imageUrl,
5665
redirectUrl = type.redirectUrl,
5766
intentData = type.intentPayload)
58-
else -> null
67+
else -> {
68+
MindboxLoggerImpl.d(this,
69+
"No innaps to show found")
70+
null
71+
}
5972
}
6073
}.filterNotNull()
6174
}
6275

6376
private fun prefilterConfig(config: InAppConfig): InAppConfig {
64-
return config.copy(inApps = config.inApps.filter { inApp -> validateInAppVersion(inApp) }
65-
.filter { inApp -> validateInAppNotShown(inApp) && validateInAppTargeting(inApp) })
77+
MindboxLoggerImpl.d(this,
78+
"Already shown innaps: ${inAppRepositoryImpl.getShownInApps()}")
79+
return config.copy(inApps = config.inApps
80+
.filter { inApp -> validateInAppNotShown(inApp) && validateInAppTargeting(inApp) }
81+
)
6682
}
6783

6884
private fun validateInAppTargeting(inApp: InApp): Boolean {
@@ -131,13 +147,6 @@ internal class InAppInteractor {
131147
}
132148
}
133149

134-
private fun validateInAppVersion(inApp: InApp): Boolean {
135-
return ((inApp.minVersion?.let { min -> min <= InAppMessageManager.CURRENT_IN_APP_VERSION }
136-
?: true) && (inApp.maxVersion?.let { max -> max >= InAppMessageManager.CURRENT_IN_APP_VERSION }
137-
?: true))
138-
}
139-
140-
141150
suspend fun fetchInAppConfig(context: Context, configuration: MindboxConfiguration) {
142151
inAppRepositoryImpl.fetchInAppConfig(context, configuration)
143152
}

sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/domain/InAppRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal interface InAppRepository {
1717
config: InAppConfig,
1818
): SegmentationCheckInApp
1919

20-
fun listenInAppConfig(): Flow<InAppConfig>
20+
fun listenInAppConfig(): Flow<InAppConfig?>
2121

2222
fun listenInAppEvents(): Flow<InAppEventType>
2323

sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/mapper/InAppMessageMapper.kt

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,58 @@ import cloud.mindbox.mobile_sdk.models.*
44
import cloud.mindbox.mobile_sdk.models.operation.request.IdsRequest
55
import cloud.mindbox.mobile_sdk.models.operation.request.SegmentationCheckRequest
66
import cloud.mindbox.mobile_sdk.models.operation.request.SegmentationDataRequest
7+
import cloud.mindbox.mobile_sdk.models.operation.response.*
78
import cloud.mindbox.mobile_sdk.models.operation.response.InAppConfigResponse
9+
import cloud.mindbox.mobile_sdk.models.operation.response.InAppConfigResponseBlank
810
import cloud.mindbox.mobile_sdk.models.operation.response.PayloadDto
911
import cloud.mindbox.mobile_sdk.models.operation.response.SegmentationCheckResponse
1012
import cloud.mindbox.mobile_sdk.models.operation.response.TargetingDto
1113

1214
internal class InAppMessageMapper {
15+
fun mapToInAppDto (
16+
inAppDtoBlank: InAppConfigResponseBlank.InAppDtoBlank,
17+
formDto: FormDto?,
18+
): InAppDto {
19+
return inAppDtoBlank.let { inApp ->
20+
InAppDto(
21+
id = inApp.id,
22+
sdkVersion = inApp.sdkVersion,
23+
targeting = inApp.targeting,
24+
form = formDto
25+
)
26+
}
27+
}
1328

14-
fun mapInAppConfigResponseToInAppConfig(inAppConfigResponse: InAppConfigResponse): InAppConfig {
15-
return InAppConfig(
16-
inAppConfigResponse.inApps?.map { inAppDto ->
17-
InApp(
18-
id = inAppDto.id,
19-
targeting = mapTargetingDtoToTargeting(inAppDto.targeting),
20-
form = Form(
21-
variants = inAppDto.form?.variants?.map { payloadDto ->
22-
when (payloadDto) {
23-
is PayloadDto.SimpleImage -> {
24-
Payload.SimpleImage(
25-
type = "",
26-
imageUrl = payloadDto.imageUrl ?: "",
27-
redirectUrl = payloadDto.redirectUrl ?: "",
28-
intentPayload = payloadDto.intentPayload ?: ""
29-
)
29+
fun mapInAppConfigResponseToInAppConfig(inAppConfigResponse: InAppConfigResponse?): InAppConfig? {
30+
return inAppConfigResponse?.let { inAppConfigDto ->
31+
InAppConfig(
32+
inAppConfigDto.inApps?.map { inAppDto ->
33+
InApp(
34+
id = inAppDto.id,
35+
targeting = mapTargetingDtoToTargeting(inAppDto.targeting),
36+
form = Form(
37+
variants = inAppDto.form?.variants?.map { payloadDto ->
38+
when (payloadDto) {
39+
is PayloadDto.SimpleImage -> {
40+
Payload.SimpleImage(
41+
type = "",
42+
imageUrl = payloadDto.imageUrl ?: "",
43+
redirectUrl = payloadDto.redirectUrl ?: "",
44+
intentPayload = payloadDto.intentPayload ?: ""
45+
)
46+
}
3047
}
31-
}
32-
} ?: emptyList()
33-
),
34-
minVersion = inAppDto.sdkVersion?.minVersion,
35-
maxVersion = inAppDto.sdkVersion?.maxVersion
36-
)
37-
} ?: emptyList()
38-
)
48+
} ?: emptyList()
49+
),
50+
minVersion = inAppDto.sdkVersion?.minVersion,
51+
maxVersion = inAppDto.sdkVersion?.maxVersion
52+
)
53+
} ?: emptyList()
54+
)
55+
}
3956
}
4057

58+
4159
private fun mapTargetingDtoToTargeting(targetingDto: TargetingDto?): Targeting? {
4260
return if (targetingDto != null) Targeting(
4361
type = targetingDto.type ?: "",

sdk/src/main/java/cloud/mindbox/mobile_sdk/inapp/presentation/InAppMessageManager.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,17 @@ internal class InAppMessageManager {
5050
if (error is VolleyError) {
5151
when (error.networkResponse?.statusCode) {
5252
CONFIG_NOT_FOUND -> {
53-
MindboxLoggerImpl.w(ERROR_TAG, error.message ?: "", error)
53+
MindboxLoggerImpl.w(this, "Config not found", error)
5454
MindboxPreferences.inAppConfig = ""
5555
}
5656
else -> {
57+
// needed to trigger flow event
5758
MindboxPreferences.inAppConfig = MindboxPreferences.inAppConfig
58-
MindboxLoggerImpl.e(ERROR_TAG, error.message ?: "", error)
59+
MindboxLoggerImpl.w(this, "Failed to get config", error)
5960
}
6061
}
6162
} else {
62-
LoggingExceptionHandler.runCatching {
63-
64-
}
63+
MindboxLoggerImpl.e(this, "Failed to get config", error)
6564
}
6665
}) {
6766
inAppInteractor.fetchInAppConfig(context, configuration)

0 commit comments

Comments
 (0)