From fa21720222dbdf3c8f21aa9b272c165dfe2c1c5e Mon Sep 17 00:00:00 2001 From: Surik Date: Wed, 15 Apr 2026 12:36:25 +0300 Subject: [PATCH 1/2] feat(nocodes): add user properties, custom variables, and forceSendProperties support Co-Authored-By: Claude Opus 4.6 (1M context) --- .../java/io/qonversion/nocodes/NoCodes.kt | 10 +++ .../io/qonversion/nocodes/NoCodesConfig.kt | 17 ++++ .../interfaces/CustomVariablesDelegate.kt | 18 +++++ .../nocodes/internal/NoCodesInternal.kt | 24 ++++++ .../di/controllers/ControllersAssemblyImpl.kt | 3 +- .../internal/dto/config/InternalConfig.kt | 3 + .../internal/screen/view/ScreenContract.kt | 3 + .../internal/screen/view/ScreenFragment.kt | 81 ++++++++++++++----- .../internal/screen/view/ScreenPresenter.kt | 36 ++++++++- .../io/qonversion/sample/NoCodesFragment.kt | 11 ++- .../com/qonversion/android/sdk/Qonversion.kt | 10 +++ .../sdk/internal/QonversionInternal.kt | 4 + 12 files changed, 198 insertions(+), 22 deletions(-) create mode 100644 nocodes/src/main/java/io/qonversion/nocodes/interfaces/CustomVariablesDelegate.kt diff --git a/nocodes/src/main/java/io/qonversion/nocodes/NoCodes.kt b/nocodes/src/main/java/io/qonversion/nocodes/NoCodes.kt index 6efd48dc..37c1b617 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/NoCodes.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/NoCodes.kt @@ -9,6 +9,7 @@ import io.qonversion.nocodes.interfaces.PurchaseDelegateWithCallbacks import io.qonversion.nocodes.internal.NoCodesInternal import io.qonversion.nocodes.internal.di.DependenciesAssembly import io.qonversion.nocodes.internal.dto.config.InternalConfig +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.interfaces.ScreenCustomizationDelegate interface NoCodes { @@ -96,6 +97,15 @@ interface NoCodes { */ fun setPurchaseDelegate(delegate: PurchaseDelegateWithCallbacks) + /** + * The delegate will be called each time a screen is about to be displayed + * to get custom variables that will be injected into the screen's JavaScript context. + * You can also provide it during the initialization via [NoCodesConfig.Builder.setCustomVariablesDelegate]. + * + * @param delegate delegate responsible for providing custom variables. + */ + fun setCustomVariablesDelegate(delegate: CustomVariablesDelegate) + /** * Show the screen using its context key. * @param contextKey the context key of the screen which must be shown. diff --git a/nocodes/src/main/java/io/qonversion/nocodes/NoCodesConfig.kt b/nocodes/src/main/java/io/qonversion/nocodes/NoCodesConfig.kt index 7ddbf434..f1002201 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/NoCodesConfig.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/NoCodesConfig.kt @@ -7,6 +7,7 @@ import io.qonversion.nocodes.dto.NoCodesTheme import io.qonversion.nocodes.interfaces.NoCodesDelegate import io.qonversion.nocodes.interfaces.PurchaseDelegate import io.qonversion.nocodes.interfaces.PurchaseDelegateWithCallbacks +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.interfaces.ScreenCustomizationDelegate import io.qonversion.nocodes.internal.dto.config.LoggerConfig import io.qonversion.nocodes.internal.dto.config.NetworkConfig @@ -32,6 +33,7 @@ class NoCodesConfig internal constructor( internal val screenCustomizationDelegate: ScreenCustomizationDelegate?, internal val purchaseDelegate: PurchaseDelegate?, internal val purchaseDelegateWithCallbacks: PurchaseDelegateWithCallbacks?, + internal val customVariablesDelegate: CustomVariablesDelegate?, internal val locale: String?, internal val theme: NoCodesTheme, ) { @@ -54,6 +56,7 @@ class NoCodesConfig internal constructor( private var screenCustomizationDelegate: ScreenCustomizationDelegate? = null private var purchaseDelegate: PurchaseDelegate? = null private var purchaseDelegateWithCallbacks: PurchaseDelegateWithCallbacks? = null + private var customVariablesDelegate: CustomVariablesDelegate? = null private var proxyUrl: String? = null private var logLevel = LogLevel.Info private var logTag = DEFAULT_LOG_TAG @@ -109,6 +112,19 @@ class NoCodesConfig internal constructor( this.purchaseDelegateWithCallbacks = purchaseDelegateWithCallbacks } + /** + * Provide a delegate to get custom variables for each No-Codes screen. + * Custom variables are injected into the screen's JavaScript context + * and can be used to influence content displayed on the screen. + * You can also provide it later via [NoCodes.setCustomVariablesDelegate]. + * + * @param customVariablesDelegate delegate responsible for providing custom variables. + * @return builder instance for chain calls. + */ + fun setCustomVariablesDelegate(customVariablesDelegate: CustomVariablesDelegate): Builder = apply { + this.customVariablesDelegate = customVariablesDelegate + } + /** * Provide a URL to your proxy server which will redirect all the requests from the No-Codes * SDK to our API. Please, contact us before using this feature. @@ -211,6 +227,7 @@ class NoCodesConfig internal constructor( screenCustomizationDelegate, purchaseDelegate, purchaseDelegateWithCallbacks, + customVariablesDelegate, locale, theme, ) diff --git a/nocodes/src/main/java/io/qonversion/nocodes/interfaces/CustomVariablesDelegate.kt b/nocodes/src/main/java/io/qonversion/nocodes/interfaces/CustomVariablesDelegate.kt new file mode 100644 index 00000000..f32c333c --- /dev/null +++ b/nocodes/src/main/java/io/qonversion/nocodes/interfaces/CustomVariablesDelegate.kt @@ -0,0 +1,18 @@ +package io.qonversion.nocodes.interfaces + +/** + * Delegate responsible for providing custom variables for No-Codes screens. + * Custom variables are injected into the screen's JavaScript context + * and can be used to influence content displayed on the screen. + */ +interface CustomVariablesDelegate { + + /** + * Provide custom variables for a specific screen identified by context key. + * Called each time a screen is about to be displayed. + * + * @param contextKey the context key of the screen being loaded. + * @return a map of custom variables to inject into the screen. + */ + fun getCustomVariables(contextKey: String): Map +} diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/NoCodesInternal.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/NoCodesInternal.kt index 19ea0f79..ef0988db 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/NoCodesInternal.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/NoCodesInternal.kt @@ -6,11 +6,13 @@ import io.qonversion.nocodes.dto.NoCodesTheme import io.qonversion.nocodes.interfaces.NoCodesDelegate import io.qonversion.nocodes.interfaces.PurchaseDelegate import io.qonversion.nocodes.interfaces.PurchaseDelegateWithCallbacks +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.interfaces.ScreenCustomizationDelegate import io.qonversion.nocodes.internal.di.DependenciesAssembly import io.qonversion.nocodes.internal.dto.config.InternalConfig import io.qonversion.nocodes.internal.dto.config.NoCodesDelegateWrapper import io.qonversion.nocodes.internal.dto.config.PurchaseDelegateWithCallbacksAdapter +import kotlin.coroutines.resume import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -55,12 +57,34 @@ internal class NoCodesInternal( internalConfig.purchaseDelegate = PurchaseDelegateWithCallbacksAdapter(delegate) } + override fun setCustomVariablesDelegate(delegate: CustomVariablesDelegate) { + internalConfig.customVariablesDelegate = delegate + } + override fun showScreen(contextKey: String) { scope.launch { + suspendFlushPendingUserProperties() screenController.showScreen(contextKey) } } + private suspend fun suspendFlushPendingUserProperties() { + kotlin.coroutines.suspendCoroutine { continuation -> + try { + com.qonversion.android.sdk.Qonversion.shared.forceSendProperties( + object : com.qonversion.android.sdk.listeners.QonversionEmptyCallback { + override fun onComplete() { + continuation.resume(Unit) + } + } + ) + } catch (e: Exception) { + logger.warn("NoCodesInternal -> Failed to flush pending user properties: ${e.message}") + continuation.resume(Unit) + } + } + } + override fun close() { runBlocking { screenEventsService.flushAndWait() diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/di/controllers/ControllersAssemblyImpl.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/di/controllers/ControllersAssemblyImpl.kt index bf3a6fea..347de7b9 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/di/controllers/ControllersAssemblyImpl.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/di/controllers/ControllersAssemblyImpl.kt @@ -37,7 +37,8 @@ internal class ControllersAssemblyImpl( mappersAssembly.actionMapper(), servicesAssembly.screenEventsService(), { miscAssembly.customLocale() }, - { miscAssembly.theme() } + { miscAssembly.theme() }, + { internalConfig.customVariablesDelegate } ) } } diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/dto/config/InternalConfig.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/dto/config/InternalConfig.kt index 88e5b89a..2a82848a 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/dto/config/InternalConfig.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/dto/config/InternalConfig.kt @@ -4,6 +4,7 @@ import io.qonversion.nocodes.NoCodesConfig import io.qonversion.nocodes.dto.LogLevel import io.qonversion.nocodes.dto.NoCodesTheme import io.qonversion.nocodes.interfaces.NoCodesDelegate +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.interfaces.PurchaseDelegate import io.qonversion.nocodes.interfaces.ScreenCustomizationDelegate import io.qonversion.nocodes.internal.provider.LocaleConfigProvider @@ -21,6 +22,7 @@ internal class InternalConfig( override var noCodesDelegate: NoCodesDelegate?, var screenCustomizationDelegate: ScreenCustomizationDelegate?, override var purchaseDelegate: PurchaseDelegate?, + var customVariablesDelegate: CustomVariablesDelegate? = null, override var customLocale: String? = null, override var theme: NoCodesTheme = NoCodesTheme.Auto, ) : PrimaryConfigProvider, @@ -40,6 +42,7 @@ internal class InternalConfig( // If PurchaseDelegate is provided, use it directly. Otherwise, wrap PurchaseDelegateWithCallbacks. noCodesConfig.purchaseDelegate ?: noCodesConfig.purchaseDelegateWithCallbacks?.let { PurchaseDelegateWithCallbacksAdapter(it) }, + noCodesConfig.customVariablesDelegate, noCodesConfig.locale, noCodesConfig.theme ) diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt index 6c760318..ecad49ee 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt @@ -27,6 +27,9 @@ internal class ScreenContract { fun handleGetContext(variables: List) fun finishScreenPreparation() + + fun setVariable(name: String, value: String, completion: () -> Unit = {}) + } internal interface Presenter { diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt index f5fbd493..c0e75ad4 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt @@ -325,23 +325,42 @@ class ScreenFragment : Fragment(), ScreenContract.View { override fun handleGetContext(variables: List) { val productIds = extractProductIds(variables) + var activeIds: List = emptyList() + var fetchedUserProperties: Map = emptyMap() + var remainingLoads = 2 + val lock = Any() + + fun onLoadComplete() { + synchronized(lock) { + remainingLoads-- + if (remainingLoads > 0) return + } + loadProductsAndSendContext(activeIds, productIds, fetchedUserProperties) + } + Qonversion.shared.checkEntitlements(object : QonversionEntitlementsCallback { override fun onSuccess(entitlements: Map) { - val activeIds = entitlements.filter { it.value.isActive }.map { it.key } - if (productIds.isNotEmpty()) { - loadProductsAndSendContext(activeIds, productIds) - } else { - sendContextResponse(activeIds, org.json.JSONObject()) - } + activeIds = entitlements.filter { it.value.isActive }.map { it.key } + onLoadComplete() } override fun onError(error: QonversionError) { logger.error("Failed to load entitlements for context: ${error.description}") - if (productIds.isNotEmpty()) { - loadProductsAndSendContext(emptyList(), productIds) - } else { - sendContextResponse(emptyList(), org.json.JSONObject()) - } + onLoadComplete() + } + }) + + Qonversion.shared.userProperties(object : com.qonversion.android.sdk.listeners.QonversionUserPropertiesCallback { + override fun onSuccess(userProperties: com.qonversion.android.sdk.dto.properties.QUserProperties) { + val map = mutableMapOf() + userProperties.properties.forEach { map[it.key] = it.value } + fetchedUserProperties = map + onLoadComplete() + } + + override fun onError(error: QonversionError) { + logger.error("Failed to load user properties for context: ${error.description}") + onLoadComplete() } }) } @@ -355,16 +374,21 @@ class ScreenFragment : Fragment(), ScreenContract.View { }.distinct() } - private fun loadProductsAndSendContext(activeIds: List, productIds: List) { + private fun loadProductsAndSendContext(activeIds: List, productIds: List, userProperties: Map = emptyMap()) { + if (productIds.isEmpty()) { + sendContextResponse(activeIds, org.json.JSONObject(), userProperties) + return + } + Qonversion.shared.products(object : QonversionProductsCallback { override fun onSuccess(products: Map) { val productsContext = buildProductsContextJSON(products, productIds) - sendContextResponse(activeIds, productsContext) + sendContextResponse(activeIds, productsContext, userProperties) } override fun onError(error: QonversionError) { logger.error("Failed to load products for context: ${error.description}") - sendContextResponse(activeIds, org.json.JSONObject()) + sendContextResponse(activeIds, org.json.JSONObject(), userProperties) } }) } @@ -399,7 +423,7 @@ class ScreenFragment : Fragment(), ScreenContract.View { return json } - private fun sendContextResponse(activeEntitlementIds: List, productsContext: org.json.JSONObject) { + private fun sendContextResponse(activeEntitlementIds: List, productsContext: org.json.JSONObject, userProperties: Map = emptyMap()) { val deviceJson = org.json.JSONObject() deviceJson.put("platform", "Android") deviceJson.put("osVersion", Build.VERSION.RELEASE) @@ -430,6 +454,9 @@ class ScreenFragment : Fragment(), ScreenContract.View { userJson.put("daysSinceInstall", calculateDaysSinceInstall()) userJson.put("hasAnyEntitlement", if (activeEntitlementIds.isNotEmpty()) "true" else "false") userJson.put("entitlements", org.json.JSONArray(activeEntitlementIds)) + if (userProperties.isNotEmpty()) { + userJson.put("properties", org.json.JSONObject(userProperties as Map<*, *>)) + } val dataJson = org.json.JSONObject() dataJson.put("device", deviceJson) @@ -450,10 +477,26 @@ class ScreenFragment : Fragment(), ScreenContract.View { } override fun finishScreenPreparation() { - binding?.progressBarLayout?.progressBar?.visibility = View.GONE - binding?.webView?.visibility = View.VISIBLE - loadingView?.stopAnimating() - binding?.loadingViewContainer?.visibility = View.GONE + activity?.runOnUiThread { + binding?.progressBarLayout?.progressBar?.visibility = View.GONE + binding?.webView?.visibility = View.VISIBLE + loadingView?.stopAnimating() + binding?.loadingViewContainer?.visibility = View.GONE + } + } + + override fun setVariable(name: String, value: String, completion: () -> Unit) { + val escapedName = name.replace("\\", "\\\\").replace("\"", "\\\"") + val escapedValue = value.replace("\\", "\\\\").replace("\"", "\\\"") + val js = "window.noCodesSetVariable?.(\"$escapedName\", \"$escapedValue\");" + val act = activity + if (act == null) { + completion() + return + } + act.runOnUiThread { + binding?.webView?.evaluateJavascript(js) { completion() } + } } @JavascriptInterface diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenPresenter.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenPresenter.kt index 2dc755cf..63a9d6a1 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenPresenter.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenPresenter.kt @@ -15,6 +15,7 @@ import io.qonversion.nocodes.error.NoCodesError import io.qonversion.nocodes.error.NoCodesException import io.qonversion.nocodes.internal.common.BaseClass import io.qonversion.nocodes.internal.common.mappers.Mapper +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.internal.common.serializers.Serializer import io.qonversion.nocodes.internal.dto.NoCodeScreen import io.qonversion.nocodes.internal.dto.ScreenEvent @@ -38,6 +39,7 @@ internal class ScreenPresenter( private val screenEventsService: ScreenEventsService, private val customLocaleProvider: () -> String? = { null }, private val themeProvider: () -> NoCodesTheme = { NoCodesTheme.Auto }, + private val customVariablesDelegateProvider: () -> CustomVariablesDelegate? = { null }, private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO), ) : ScreenContract.Presenter, BaseClass(logger) { @@ -165,7 +167,9 @@ internal class ScreenPresenter( view.handleGetContext(variables) } QAction.Type.ShowScreen -> { - view.finishScreenPreparation() + injectCustomVariables { + view.finishScreenPreparation() + } } QAction.Type.Navigation -> { action.parameters?.get(QAction.Parameter.ScreenId)?.let { screenId -> @@ -338,6 +342,36 @@ internal class ScreenPresenter( return res } + private fun injectCustomVariables(completion: () -> Unit) { + val contextKey = currentScreen?.contextKey + if (contextKey == null) { + completion() + return + } + val delegate = customVariablesDelegateProvider() + if (delegate == null) { + completion() + return + } + val variables = delegate.getCustomVariables(contextKey) + if (variables.isEmpty()) { + completion() + return + } + + val entries = variables.entries.toList() + var remaining = entries.size + + for ((name, value) in entries) { + view.setVariable(name, value) { + remaining-- + if (remaining == 0) { + completion() + } + } + } + } + private fun loadNextScreen(screenId: String) { try { scope.launch { diff --git a/sample/src/main/java/io/qonversion/sample/NoCodesFragment.kt b/sample/src/main/java/io/qonversion/sample/NoCodesFragment.kt index 203fd4cc..c4d49720 100644 --- a/sample/src/main/java/io/qonversion/sample/NoCodesFragment.kt +++ b/sample/src/main/java/io/qonversion/sample/NoCodesFragment.kt @@ -10,10 +10,11 @@ import io.qonversion.nocodes.NoCodes import io.qonversion.nocodes.dto.NoCodesTheme import io.qonversion.nocodes.dto.QAction import io.qonversion.nocodes.error.NoCodesError +import io.qonversion.nocodes.interfaces.CustomVariablesDelegate import io.qonversion.nocodes.interfaces.NoCodesDelegate import io.qonversion.sample.databinding.FragmentNocodesBinding -class NoCodesFragment : Fragment(), NoCodesDelegate { +class NoCodesFragment : Fragment(), NoCodesDelegate, CustomVariablesDelegate { private var _binding: FragmentNocodesBinding? = null private val binding get() = _binding!! @@ -78,9 +79,17 @@ class NoCodesFragment : Fragment(), NoCodesDelegate { private fun setupNoCodes() { NoCodes.shared.setDelegate(this) + NoCodes.shared.setCustomVariablesDelegate(this) addEvent(getString(R.string.nocodes_delegate_set)) } + // CustomVariablesDelegate + override fun getCustomVariables(contextKey: String): Map { + val variables = mapOf("custom_var" to "super") + android.util.Log.d("NoCodes", "Custom variables requested for $contextKey: $variables") + return variables + } + private fun showScreen(contextKey: String) { addEvent(getString(R.string.showing_screen, contextKey)) NoCodes.shared.showScreen(contextKey) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/Qonversion.kt b/sdk/src/main/java/com/qonversion/android/sdk/Qonversion.kt index 7ff0cb33..0a930375 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/Qonversion.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/Qonversion.kt @@ -9,6 +9,7 @@ import com.qonversion.android.sdk.dto.products.QProduct import com.qonversion.android.sdk.dto.properties.QUserPropertyKey import com.qonversion.android.sdk.internal.InternalConfig import com.qonversion.android.sdk.internal.QonversionInternal +import com.qonversion.android.sdk.listeners.QonversionEmptyCallback import com.qonversion.android.sdk.listeners.QonversionExperimentAttachCallback import com.qonversion.android.sdk.listeners.QDeferredPurchasesListener import com.qonversion.android.sdk.listeners.QEntitlementsUpdateListener @@ -346,6 +347,15 @@ interface Qonversion { */ fun userProperties(callback: QonversionUserPropertiesCallback) + /** + * Force-flushes any pending user property updates to the server immediately. + * Use this when you need to ensure all previously set properties have been sent + * before performing an operation that depends on them. + * + * @param callback callback that will be called when the flush is complete. + */ + fun forceSendProperties(callback: QonversionEmptyCallback) + /** * Call this function to check if the fallback file is accessible. * @return flag that indicates whether Qonversion was able to read data from the fallback file or not. diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt index 5b75b611..7b1af8f3 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt @@ -368,6 +368,10 @@ internal class QonversionInternal( userPropertiesManager.userProperties(callback) } + override fun forceSendProperties(callback: com.qonversion.android.sdk.listeners.QonversionEmptyCallback) { + userPropertiesManager.forceSendProperties(callback) + } + override fun isFallbackFileAccessible(): Boolean { val fallbackObject = fallbackService.obtainFallbackData() From 6bfd19131da1a44e9ec1d3d5913b4c22184c0710 Mon Sep 17 00:00:00 2001 From: Surik Date: Wed, 15 Apr 2026 12:48:28 +0300 Subject: [PATCH 2/2] fix: update detekt baseline and fix code formatting Co-Authored-By: Claude Opus 4.6 (1M context) --- config/detekt/baseline.xml | 6 ++++-- .../nocodes/internal/screen/view/ScreenContract.kt | 1 - .../nocodes/internal/screen/view/ScreenFragment.kt | 12 ++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index e3652717..256ecbb5 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -19,7 +19,6 @@ EmptyFunctionBlock:QProductCenterManager.kt$QProductCenterManager.<no name provided>${} Filename:com.qonversion.android.sdk.internal.storage.util.kt:1 FinalNewline:com.qonversion.android.sdk.internal.IncrementalDelayCalculatorTest.kt:1 - FinalNewline:com.qonversion.android.sdk.internal.InternalConfigTest.kt:1 FinalNewline:com.qonversion.android.sdk.internal.QHandledPurchasesCacheTest.kt:1 FinalNewline:com.qonversion.android.sdk.internal.QProductCenterManagerTest.kt:1 FinalNewline:com.qonversion.android.sdk.internal.QUserPropertiesManagerTest.kt:1 @@ -33,6 +32,7 @@ FinalNewline:com.qonversion.android.sdk.utils.kt:1 LargeClass:QProductCenterManager.kt$QProductCenterManager : PurchasesListenerUserStateProvider LongMethod:NoCodesSkeletonView.kt$NoCodesSkeletonView$private fun createSkeletonElements() + LongMethod:ScreenPresenter.kt$ScreenPresenter$override fun onWebViewMessageReceived(message: String) MagicNumber:ApiErrorMapper.kt$ApiErrorMapper$10002 MagicNumber:ApiErrorMapper.kt$ApiErrorMapper$10003 MagicNumber:ApiErrorMapper.kt$ApiErrorMapper$10004 @@ -95,7 +95,6 @@ NewLineAtEndOfFile:ApiHelperTest.kt$com.qonversion.android.sdk.internal.api.ApiHelperTest.kt NewLineAtEndOfFile:AppRequestTest.kt$com.qonversion.android.sdk.internal.requests.AppRequestTest.kt NewLineAtEndOfFile:IncrementalDelayCalculatorTest.kt$com.qonversion.android.sdk.internal.IncrementalDelayCalculatorTest.kt - NewLineAtEndOfFile:InternalConfigTest.kt$com.qonversion.android.sdk.internal.InternalConfigTest.kt NewLineAtEndOfFile:OsRequestTest.kt$com.qonversion.android.sdk.internal.requests.OsRequestTest.kt NewLineAtEndOfFile:ProviderDataRequestTest.kt$com.qonversion.android.sdk.internal.requests.ProviderDataRequestTest.kt NewLineAtEndOfFile:PurchasesCacheTest.kt$com.qonversion.android.sdk.internal.storage.PurchasesCacheTest.kt @@ -111,6 +110,8 @@ NoConsecutiveBlankLines:com.qonversion.android.sdk.internal.requests.ProviderDataRequestTest.kt:18 NoWildcardImports:com.qonversion.android.sdk.dto.products.QProduct.kt:3 NoWildcardImports:com.qonversion.android.sdk.internal.AdvertisingProvider.kt:7 + NoWildcardImports:com.qonversion.android.sdk.internal.DeferredPurchasesListenerTest.kt:8 + NoWildcardImports:com.qonversion.android.sdk.internal.DeferredPurchasesListenerTest.kt:9 NoWildcardImports:com.qonversion.android.sdk.internal.EnvironmentProvider.kt:11 NoWildcardImports:com.qonversion.android.sdk.internal.IncrementalDelayCalculator.kt:3 NoWildcardImports:com.qonversion.android.sdk.internal.IncrementalDelayCalculatorTest.kt:3 @@ -139,6 +140,7 @@ ReturnCount:QProductCenterManager.kt$QProductCenterManager$@Synchronized private fun executeProductsBlocks(loadStoreProductsError: QonversionError? = null) ReturnCount:QProductCenterManager.kt$QProductCenterManager$fun identify(identityId: String, callback: QonversionUserCallback? = null) ReturnCount:QProductCenterManager.kt$QProductCenterManager$private fun calculatePurchasePermissionsLocally( purchase: Purchase, callback: QonversionPurchaseCallback?, purchaseError: QonversionError ) + ReturnCount:ScreenPresenter.kt$ScreenPresenter$private fun injectCustomVariables(completion: () -> Unit) SpacingAroundColon:com.qonversion.android.sdk.internal.requests.ProviderDataRequestTest.kt:45 SpacingAroundCurly:com.qonversion.android.sdk.internal.QAttributionManagerTest.kt:39 SpacingAroundCurly:com.qonversion.android.sdk.internal.QAttributionManagerTest.kt:54 diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt index ecad49ee..3c83f1b5 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenContract.kt @@ -29,7 +29,6 @@ internal class ScreenContract { fun finishScreenPreparation() fun setVariable(name: String, value: String, completion: () -> Unit = {}) - } internal interface Presenter { diff --git a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt index c0e75ad4..092b479e 100644 --- a/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt +++ b/nocodes/src/main/java/io/qonversion/nocodes/internal/screen/view/ScreenFragment.kt @@ -374,7 +374,11 @@ class ScreenFragment : Fragment(), ScreenContract.View { }.distinct() } - private fun loadProductsAndSendContext(activeIds: List, productIds: List, userProperties: Map = emptyMap()) { + private fun loadProductsAndSendContext( + activeIds: List, + productIds: List, + userProperties: Map = emptyMap() + ) { if (productIds.isEmpty()) { sendContextResponse(activeIds, org.json.JSONObject(), userProperties) return @@ -423,7 +427,11 @@ class ScreenFragment : Fragment(), ScreenContract.View { return json } - private fun sendContextResponse(activeEntitlementIds: List, productsContext: org.json.JSONObject, userProperties: Map = emptyMap()) { + private fun sendContextResponse( + activeEntitlementIds: List, + productsContext: org.json.JSONObject, + userProperties: Map = emptyMap() + ) { val deviceJson = org.json.JSONObject() deviceJson.put("platform", "Android") deviceJson.put("osVersion", Build.VERSION.RELEASE)