From 64146b98e8b0848913fb727d8c46a9a43c6a29ce Mon Sep 17 00:00:00 2001 From: swapnilWingify Date: Tue, 5 Nov 2024 16:05:07 +0530 Subject: [PATCH] feat: MEG personalize and in-built storage support --- CHANGELOG.md | 19 +- app/src/main/AndroidManifest.xml | 3 + .../java/com/vwo/fme/JavaMainActivity.java | 168 +++++ app/src/main/java/com/vwo/fme/MainActivity.kt | 140 +++- app/src/main/java/com/vwo/fme/StorageTest.kt | 73 ++ app/src/main/res/layout/activity_main.xml | 11 + app/src/main/res/values/strings.xml | 1 + build.gradle | 4 +- fme-android/build.gradle | 15 +- fme-android/proguard-rules.pro | 3 +- .../src/main/assets/debug-messages.json | 1 + .../src/main/assets/error-messages.json | 6 +- fme-android/src/main/java/com/vwo/VWO.kt | 28 +- .../src/main/java/com/vwo/VWOBuilder.kt | 57 +- .../src/main/java/com/vwo/VWOClient.kt | 15 +- .../src/main/java/com/vwo/api/GetFlagAPI.kt | 86 ++- .../main/java/com/vwo/api/SetAttributeAPI.kt | 1 + .../main/java/com/vwo/api/TrackEventAPI.kt | 4 +- .../main/java/com/vwo/constants/Constants.kt | 6 +- .../com/vwo/decorators/StorageDecorator.kt | 2 +- .../src/main/java/com/vwo/enums/EventEnum.kt | 4 +- .../src/main/java/com/vwo/enums/UrlEnum.kt | 6 +- .../java/com/vwo/enums/VariableTypeEnum.kt | 21 + .../java/com/vwo/interfaces/IVwoListener.java | 38 + .../src/main/java/com/vwo/models/Campaign.kt | 11 + .../src/main/java/com/vwo/models/Groups.kt | 7 +- .../java/com/vwo/models/RecommendedProduct.kt | 28 + .../src/main/java/com/vwo/models/Variable.kt | 3 + .../src/main/java/com/vwo/models/Variation.kt | 11 + .../main/java/com/vwo/models/user/GetFlag.kt | 38 +- .../com/vwo/models/user/Recommendation.kt | 115 +++ .../java/com/vwo/models/user/VWOContext.kt | 1 + .../com/vwo/models/user/VWOInitOptions.kt | 9 +- .../network_layer/client/ApiCallRepeater.kt | 100 +++ .../network_layer/client/NetworkClient.kt | 176 +++-- .../network_layer/manager/NetworkManager.kt | 10 +- .../network_layer/models/RequestModel.kt | 2 - .../core/SegmentationManager.kt | 15 +- .../evaluators/SegmentEvaluator.kt | 2 +- .../evaluators/SegmentOperandEvaluator.kt | 2 +- .../vwo/packages/storage/DefaultStorage.kt | 73 ++ .../storage/LocalStorageController.kt | 95 +++ .../packages/storage/MobileDefaultStorage.kt | 99 +++ .../com/vwo/packages/storage/RequestStore.kt | 108 +++ .../com/vwo/packages/storage/SettingsStore.kt | 88 +++ .../java/com/vwo/providers/StorageProvider.kt | 47 ++ .../vwo/services/CampaignDecisionService.kt | 62 +- .../java/com/vwo/services/SettingsManager.kt | 86 ++- .../java/com/vwo/services/StorageService.kt | 2 +- .../com/vwo/utils/AppLifecycleListener.kt | 130 ++++ .../main/java/com/vwo/utils/CampaignUtil.kt | 107 ++- .../main/java/com/vwo/utils/DataTypeUtil.kt | 12 + .../main/java/com/vwo/utils/DecisionUtil.kt | 282 ++++++-- .../main/java/com/vwo/utils/EventsUtils.kt | 85 +++ .../java/com/vwo/utils/GatewayServiceUtil.kt | 6 +- .../main/java/com/vwo/utils/ImpressionUtil.kt | 1 + .../src/main/java/com/vwo/utils/MegUtil.kt | 265 ++++--- .../main/java/com/vwo/utils/NetworkUtil.kt | 56 +- .../java/com/vwo/utils/RecommendationUtil.kt | 102 +++ .../java/com/vwo/utils/RuleEvaluationUtil.kt | 2 +- .../main/java/com/vwo/utils/SettingsUtil.kt | 32 +- .../src/main/java/com/vwo/utils/UUIDUtils.kt | 102 ++- .../src/test/java/com/vwo/e2e/GetFlagTests.kt | 142 ++++ .../packages/segmentor/AndOperatorTests.kt | 183 +++++ .../CaseInsensitiveEqualityOperandTests.kt | 489 +++++++++++++ .../packages/segmentor/CombinationTests.kt | 679 ++++++++++++++++++ .../segmentor/ContainsOperandTests.kt | 457 ++++++++++++ .../segmentor/EndsWithOperandTests.kt | 501 +++++++++++++ .../segmentor/EqualityOperandTests.kt | 488 +++++++++++++ .../GreaterThanEqualToOperatorTests.kt | 94 +++ .../segmentor/GreaterThanOperatorTests.kt | 94 +++ .../segmentor/LessThanEqualToOperatorTests.kt | 75 ++ .../segmentor/LessThanOperatorTests.kt | 94 +++ .../packages/segmentor/NotOperatorTests.kt | 563 +++++++++++++++ .../vwo/packages/segmentor/OrOperatorTests.kt | 159 ++++ .../com/vwo/packages/segmentor/RegexTests.kt | 124 ++++ .../packages/segmentor/SegmentorTestUtils.kt | 29 + .../segmentor/StartsWithOperandTests.kt | 451 ++++++++++++ .../java/com/vwo/testcases/Expectation.kt | 36 + .../test/java/com/vwo/testcases/TestCases.kt | 32 + .../test/java/com/vwo/testcases/TestData.kt | 26 + .../java/com/vwo/testcases/TestDataReader.kt | 62 ++ .../java/com/vwo/utils/DummySettingsReader.kt | 56 ++ .../resources/BASIC_ROLLOUT_SETTINGS.json | 73 ++ .../BASIC_ROLLOUT_TESTING_RULE_SETTINGS.json | 164 +++++ .../MEG_CAMPAIGN_ADVANCE_ALGO_SETTINGS.json | 639 ++++++++++++++++ .../MEG_CAMPAIGN_RANDOM_ALGO_SETTINGS.json | 444 ++++++++++++ ...NO_ROLLOUT_ONLY_TESTING_RULE_SETTINGS.json | 163 +++++ ...OUT_TESTING_PRE_SEGMENT_RULE_SETTINGS.json | 329 +++++++++ ...NG_WHITELISTING_SEGMENT_RULE_SETTINGS.json | 184 +++++ .../test/resources/assets/debug-messages.json | 13 + .../test/resources/assets/error-messages.json | 27 + .../test/resources/assets/info-messages.json | 31 + .../test/resources/assets/trace-messages.json | 1 + .../test/resources/assets/warn-messages.json | 1 + fme-android/src/test/resources/index.json | 587 +++++++++++++++ .../src/test/resources/testData/index.json | 587 +++++++++++++++ gradle.properties | 6 +- 98 files changed, 10728 insertions(+), 439 deletions(-) create mode 100644 app/src/main/java/com/vwo/fme/JavaMainActivity.java create mode 100644 app/src/main/java/com/vwo/fme/StorageTest.kt create mode 100644 fme-android/src/main/java/com/vwo/enums/VariableTypeEnum.kt create mode 100644 fme-android/src/main/java/com/vwo/interfaces/IVwoListener.java create mode 100644 fme-android/src/main/java/com/vwo/models/RecommendedProduct.kt create mode 100644 fme-android/src/main/java/com/vwo/models/user/Recommendation.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/network_layer/client/ApiCallRepeater.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/storage/DefaultStorage.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/storage/LocalStorageController.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/storage/MobileDefaultStorage.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/storage/RequestStore.kt create mode 100644 fme-android/src/main/java/com/vwo/packages/storage/SettingsStore.kt create mode 100644 fme-android/src/main/java/com/vwo/providers/StorageProvider.kt create mode 100644 fme-android/src/main/java/com/vwo/utils/AppLifecycleListener.kt create mode 100644 fme-android/src/main/java/com/vwo/utils/EventsUtils.kt create mode 100644 fme-android/src/main/java/com/vwo/utils/RecommendationUtil.kt create mode 100644 fme-android/src/test/java/com/vwo/e2e/GetFlagTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/AndOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/CaseInsensitiveEqualityOperandTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/CombinationTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/ContainsOperandTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/EndsWithOperandTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/EqualityOperandTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/GreaterThanEqualToOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/GreaterThanOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/LessThanEqualToOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/LessThanOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/NotOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/OrOperatorTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/RegexTests.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/SegmentorTestUtils.kt create mode 100644 fme-android/src/test/java/com/vwo/packages/segmentor/StartsWithOperandTests.kt create mode 100644 fme-android/src/test/java/com/vwo/testcases/Expectation.kt create mode 100644 fme-android/src/test/java/com/vwo/testcases/TestCases.kt create mode 100644 fme-android/src/test/java/com/vwo/testcases/TestData.kt create mode 100644 fme-android/src/test/java/com/vwo/testcases/TestDataReader.kt create mode 100644 fme-android/src/test/java/com/vwo/utils/DummySettingsReader.kt create mode 100644 fme-android/src/test/resources/BASIC_ROLLOUT_SETTINGS.json create mode 100644 fme-android/src/test/resources/BASIC_ROLLOUT_TESTING_RULE_SETTINGS.json create mode 100644 fme-android/src/test/resources/MEG_CAMPAIGN_ADVANCE_ALGO_SETTINGS.json create mode 100644 fme-android/src/test/resources/MEG_CAMPAIGN_RANDOM_ALGO_SETTINGS.json create mode 100644 fme-android/src/test/resources/NO_ROLLOUT_ONLY_TESTING_RULE_SETTINGS.json create mode 100644 fme-android/src/test/resources/ROLLOUT_TESTING_PRE_SEGMENT_RULE_SETTINGS.json create mode 100644 fme-android/src/test/resources/TESTING_WHITELISTING_SEGMENT_RULE_SETTINGS.json create mode 100644 fme-android/src/test/resources/assets/debug-messages.json create mode 100644 fme-android/src/test/resources/assets/error-messages.json create mode 100644 fme-android/src/test/resources/assets/info-messages.json create mode 100644 fme-android/src/test/resources/assets/trace-messages.json create mode 100644 fme-android/src/test/resources/assets/warn-messages.json create mode 100644 fme-android/src/test/resources/index.json create mode 100644 fme-android/src/test/resources/testData/index.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 29823b9..0e58bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,24 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -[0.1.0] - 2024-07-31 +## [1.0.0] - 2024-11-11 ### Added + +- Added support for Personalise rules within `Mutually Exclusive Groups`. +- Settings cache: Cached settings will be used till it expires. Client can set the expiry time of cache. +- Storage support: Built-in local storage will be used by default if client doesn't provide their own. Client’s storage will be used if it is provided. +- Call backs added to avoid busy waiting for server call to complete. +- Changed variable access to method access for Flag - setIsEnabled & isEnabled + +## [0.1.0] - 2024-07-31 + +### Added + - First release of VWO Feature Management and Experimentation capabilities. ```kotlin @@ -53,9 +65,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Log.d("Vwo", "vwoInitFailed: $message") } }) - - ``` + ``` - **Error handling** - - Gracefully handle any kind of error - TypeError, NetworkError, etc. \ No newline at end of file + - Gracefully handle any kind of error - TypeError, NetworkError, etc. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9534303..24375ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ android:supportsRtl="true" android:theme="@style/Theme.FME" tools:targetApi="31"> + @@ -21,6 +22,8 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/vwo/fme/JavaMainActivity.java b/app/src/main/java/com/vwo/fme/JavaMainActivity.java new file mode 100644 index 0000000..a07a7df --- /dev/null +++ b/app/src/main/java/com/vwo/fme/JavaMainActivity.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024 Wingify Software Pvt. Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.vwo.fme; + +import android.os.Bundle; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.vwo.VWO; +import com.vwo.fme.databinding.ActivityMainBinding; +import com.vwo.interfaces.IVwoInitCallback; +import com.vwo.interfaces.IVwoListener; +import com.vwo.models.user.GetFlag; +import com.vwo.models.user.VWOContext; +import com.vwo.models.user.VWOInitOptions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JavaMainActivity extends AppCompatActivity { + + TestApp prod = new TestApp(0, + "", + "flag-name", + "variable-name", + "event-name", + "attribute-name"); + + TestApp server = prod; + String SDK_KEY = server.getSdkKey(); + int ACCOUNT_ID = server.getAccountId(); + + private VWO vwo; + private GetFlag featureFlag; + private VWOContext userContext; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + binding.tvName.setText("FME Java"); + + binding.btnInitSdk.setOnClickListener(view -> { + VWOInitOptions vwoInitOptions = new VWOInitOptions(); + vwoInitOptions.setSdkKey(SDK_KEY); + vwoInitOptions.setAccountId(ACCOUNT_ID); + + Map loggerOptions = new HashMap<>(); + loggerOptions.put("level", "TRACE"); + vwoInitOptions.setLogger(loggerOptions); + + VWO.init(vwoInitOptions, new IVwoInitCallback() { + @Override + public void vwoInitSuccess(@NonNull VWO vwo, @NonNull String message) { + Log.d("Flag", "vwoInitSuccess " + message); + JavaMainActivity.this.vwo = vwo; + } + + @Override + public void vwoInitFailed(@NonNull String message) { + Log.d("Flag", "vwoInitFailed: " + message); + } + }); + }); + binding.btnGetFlag.setOnClickListener(v -> { + if (vwo != null) { + getFlag(vwo); + } + }); + + binding.btnGetVariable.setOnClickListener(v -> { + if (featureFlag != null) { + getVariable(featureFlag); + } + }); + + binding.btnTrack.setOnClickListener(v -> track()); + + binding.btnAttribute.setOnClickListener(v -> sendAttribute()); + binding.btnJavaScreen.setVisibility(View.GONE); + } + + private void getFlag(@NonNull VWO vwo) { + userContext = new VWOContext(); + userContext.setId("unique_user_id"); + + Map customVariables = new HashMap<>(); + customVariables.put("Username", "Swapnil"); + customVariables.put("userType", "trial"); + userContext.setCustomVariables(customVariables); + + vwo.getFlag("feature-key", userContext, new IVwoListener() { + public void onSuccess(Object data) { + featureFlag = (GetFlag) data; + if (featureFlag != null) { + boolean isFeatureFlagEnabled = featureFlag.isEnabled(); + Log.d("FME-App", "Received getFlag isFeatureFlagEnabled=" + isFeatureFlagEnabled); + } + } + + public void onFailure(@NonNull String message) { + Log.d("FME-App", "getFlag " + message); + } + }); + if (featureFlag == null) + return; + boolean isFeatureFlagEnabled = featureFlag.isEnabled(); + + Log.d("Flag", "isFeatureFlagEnabled=" + isFeatureFlagEnabled); + } + + private void getVariable(@NonNull GetFlag featureFlag) { + boolean isFeatureFlagEnabled = featureFlag.isEnabled(); + Log.d("Flag", "isFeatureFlagEnabled=" + isFeatureFlagEnabled); + + if (isFeatureFlagEnabled) { + String variable1 = (String) featureFlag.getVariable("variable_key", "default-value1"); + + List> getAllVariables = featureFlag.getVariables(); + Log.d("Flag", "variable1=" + variable1 + " getAllVariables=" + getAllVariables); + } else { + Log.d("Flag", "Feature flag is disabled: " + featureFlag.isEnabled() + " " + featureFlag.getVariables()); + } + } + + private void track() { + if (userContext == null) return; + + Map properties = new HashMap<>(); + properties.put("cartvalue", 120); + properties.put("productCountInCart", 2); + + // Track the event for the given event name, user context and properties + Map trackResponse = vwo.trackEvent("productViewed", userContext, properties); + Log.d("Flag", "track=" + trackResponse); + // Track the event for the given event name and user context + //Map trackResponse = vwo.trackEvent("vwoevent", userContext); + } + + private void sendAttribute() { + if (vwo != null) { + vwo.setAttribute("userType", "paid", userContext); + vwo.setAttribute("attribute-name-float", 1.01, userContext); + vwo.setAttribute("attribute-name-boolean", true, userContext); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vwo/fme/MainActivity.kt b/app/src/main/java/com/vwo/fme/MainActivity.kt index 7629d14..8d265ce 100644 --- a/app/src/main/java/com/vwo/fme/MainActivity.kt +++ b/app/src/main/java/com/vwo/fme/MainActivity.kt @@ -1,22 +1,37 @@ package com.vwo.fme +import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import com.vwo.VWO import com.vwo.fme.databinding.ActivityMainBinding import com.vwo.interfaces.IVwoInitCallback +import com.vwo.interfaces.IVwoListener import com.vwo.models.user.GetFlag +import com.vwo.models.user.Recommendation import com.vwo.models.user.VWOContext import com.vwo.models.user.VWOInitOptions +import com.vwo.services.LoggerService +val prod = TestApp( + accountId = 0, + sdkKey = "", + flagName = "", + variableName = "", + eventName = "", + attributeName = "" +) -private const val SDK_KEY = "" -private const val ACCOUNT_ID = 0 +val server = prod +private val SDK_KEY = server.sdkKey +private val ACCOUNT_ID = server.accountId class MainActivity : AppCompatActivity() { + private val USER_ID = "" private var vwo: VWO? = null private var featureFlag: GetFlag? = null private lateinit var userContext: VWOContext @@ -37,8 +52,16 @@ class MainActivity : AppCompatActivity() { // Set SDK Key and Account ID vwoInitOptions.sdkKey = SDK_KEY vwoInitOptions.accountId = ACCOUNT_ID + vwoInitOptions.context = this@MainActivity.applicationContext vwoInitOptions.logger = mutableMapOf().apply { put("level", "TRACE") } + /*vwoInitOptions.gatewayService = mutableMapOf().apply { + put("url", "http://10.0.2.2:8000") + }*/ + //vwoInitOptions.pollInterval = 60000 + vwoInitOptions.cachedSettingsExpiryTime = 2 * 60 * 1000 // 2 min + + //vwoInitOptions.storage = StorageTest() // Create VWO instance with the vwoInitOptions VWO.init(vwoInitOptions, object : IVwoInitCallback { override fun vwoInitSuccess(vwo: VWO, message: String) { @@ -50,24 +73,30 @@ class MainActivity : AppCompatActivity() { // Log error here } }) - binding.btnGetFlag.setOnClickListener { - vwo?.let { getFlag(it) } - } - binding.btnGetVariable.setOnClickListener { - featureFlag?.let { getVariable(it) } - } - binding.btnTrack.setOnClickListener { - track() - } - binding.btnAttribute.setOnClickListener { - sendAttribute() - } + } + binding.btnGetFlag.setOnClickListener { + vwo?.let { getFlag(it) } + } + binding.btnGetVariable.setOnClickListener { + featureFlag?.let { getVariable(it) } + } + binding.btnTrack.setOnClickListener { + track() + } + binding.btnAttribute.setOnClickListener { + sendAttribute() + } + binding.btnJavaScreen.setOnClickListener { + startActivity(Intent(this, JavaMainActivity::class.java)) } } private fun getFlag(vwo: VWO) { userContext = VWOContext() - userContext.id = "unique_user_id" + userContext.id = USER_ID + userContext.ipAddress = "182.69.183.212" + //userContext.userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" + userContext.userAgent = "AppName/1.0 (Linux; Android 12; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Mobile Safari/537.36" userContext.customVariables = mutableMapOf( "name1" to 21, "name2" to 0, @@ -76,42 +105,105 @@ class MainActivity : AppCompatActivity() { ) // Get feature flag object - featureFlag = vwo.getFlag("feature_flag_name", userContext) + vwo.getFlag(server.flagName, userContext, object : IVwoListener { + override fun onSuccess(data: Any) { + featureFlag = data as? GetFlag + val isFeatureFlagEnabled = featureFlag?.isEnabled() + Log.d("FME-App", "Received getFlag isFeatureFlagEnabled=$isFeatureFlagEnabled") + } - val isFeatureFlagEnabled = featureFlag?.isEnabled + override fun onFailure(message: String) { + Log.d("FME-App", "getFlag $message") + } + }) } private fun getVariable(featureFlag: GetFlag) { - val isFeatureFlagEnabled = featureFlag.isEnabled + val isFeatureFlagEnabled = featureFlag.isEnabled() // Determine the application flow based on feature flag status if (isFeatureFlagEnabled) { // To get value of a single variable - val variable1 = featureFlag.getVariable("feature_flag_variable1", "default-value1") - val variable2 = featureFlag.getVariable("feature_flag_variable2", "default-value2") + recommendation(featureFlag) + val variable2 = featureFlag.getVariable(server.variableName, "default-value2") // To get value of all variables in object format val getAllVariables = featureFlag.getVariables() + println("Variable values: getAllVariables=$getAllVariables") } else { // Your code when feature flag is disabled } } + private fun recommendation(featureFlag: GetFlag) { + + val recommendationWrapper = featureFlag.getVariable(server.variableName, "default") + + if (recommendationWrapper is Recommendation) { + val options = mapOf( + "userId" to USER_ID, + "productIds" to "1,2,3,4", + "pageType" to "shopping-cart-page-view" + ) + recommendationWrapper.getRecommendations( + options, + category = "Clothing", + productIds = listOf(1501), + object : IVwoListener { + + override fun onSuccess(data: Any) { + println("response is -- $data") + } + + override fun onFailure(message: String) { + println("error is -- $message") + } + }) + recommendationWrapper.getRecommendationWidget( + featureFlag, + emptyMap(), + object : IVwoListener { + override fun onSuccess(data: Any) { + println("getRecommendationWidget response is -- $data") + } + + override fun onFailure(message: String) { + println("getRecommendationWidget error is -- $message") + } + }) + println("RecommendationBlock=${recommendationWrapper.recommendationBlock}") + } + } + private fun track() { if (!::userContext.isInitialized) return val properties = mutableMapOf("cartvalue" to 10) // Track the event for the given event name and user context - val trackResponse = vwo?.trackEvent("vwoevent", userContext, properties) - //val trackResponse = vwo?.trackEvent("vwoevent", userContext) + val map: MutableMap = mutableMapOf() + map["category"] = "electronics" + map["isWishlisted"] = false + map["price"] = 21 + map["productId"] = 1 + val trackResponse = vwo?.trackEvent(server.eventName, userContext, map) + //val trackResponse = vwo?.trackEvent(server.eventName, userContext) } private fun sendAttribute() { if (!::userContext.isInitialized) return - vwo?.setAttribute("attribute-name", "attribute-value1", userContext) + vwo?.setAttribute(server.attributeName, "attribute-value1", userContext) vwo?.setAttribute("attribute-name-float", 1.01, userContext) vwo?.setAttribute("attribute-name-boolean", true, userContext) } -} \ No newline at end of file +} + +data class TestApp( + val accountId: Int, + val sdkKey: String, + val flagName: String, + val variableName: String, + val eventName: String, + val attributeName: String +) \ No newline at end of file diff --git a/app/src/main/java/com/vwo/fme/StorageTest.kt b/app/src/main/java/com/vwo/fme/StorageTest.kt new file mode 100644 index 0000000..1923eb5 --- /dev/null +++ b/app/src/main/java/com/vwo/fme/StorageTest.kt @@ -0,0 +1,73 @@ +/** + * Copyright 2024 Wingify Software Pvt. Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vwo.fme + +import com.vwo.packages.storage.Connector + +/** + * A class for storing and retrieving data from a storage. + */ +class StorageTest : Connector() { + /** + * A In-memory mutable map to store the data. + * The keys are strings representing a combination of feature key and user ID. + * The values are maps containing the data for each key. + */ + private val storage: MutableMap> = HashMap() + + /** + * Stores the data in the storage. + * + * @param data A map containing the data to be stored. + * The map should contain the following keys: + * - "featureKey": The feature key for the data. + * - "user": The user ID for the data. + * - "rolloutKey": The rollout key for the data. + * - "rolloutVariationId": The rollout variation ID for the data. + * - "experimentKey": The experimentkey for the data. + * - "experimentVariationId": The experiment variation ID for the data. + */ + override fun set(data: Map) { + val key = data["featureKey"].toString() + "_" + data["userId"] + + // Create a map to store the data + val value: MutableMap = HashMap() + value["rolloutKey"] = data["rolloutKey"] + value["rolloutVariationId"] = data["rolloutVariationId"] + value["experimentKey"] = data["experimentKey"] + value["experimentVariationId"] = data["experimentVariationId"] + + // Store the value in the storage + storage[key] = value + } + + /** + * Retrieves the data from the storage. + * + * @param featureKey The feature key for the data. + * @param userId The user ID for the data. + * @return The data if found, or null otherwise. + */ + override fun get(featureKey: String?, userId: String?): Any? { + val key = featureKey + "_" + userId + + // Check if the key exists in the storage + if (storage.containsKey(key)) { + return storage[key] + } + return null + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 60eed50..4459418 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,6 +8,7 @@ tools:context=".MainActivity"> + +