diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 017f895..0e0a007 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,9 +1,8 @@ plugins { - id(BuildSystem.plugins. - androidApplication) + id(BuildSystem.plugins.androidApplication) id(BuildSystem.plugins.kotlinAndroid) - id(BuildSystem.plugins.extensions) id("com.google.gms.google-services") + id("kotlin-kapt") id("org.jetbrains.kotlin.android") } @@ -13,6 +12,8 @@ apply { android { + namespace = "com.teavaro.ecommDemoApp" + defaultConfig { applicationId = "com.teavaro.ecommDemoApp" minSdk = BuildSystem.versions.minSdk @@ -34,10 +35,14 @@ android { } viewBinding { - isEnabled = true + enable = true + } + + buildFeatures { + buildConfig = true } - packagingOptions { + packaging { resources.excludes.addAll(listOf( "META-INF/DEPENDENCIES", "META-INF/LICENSE-notice.md", @@ -62,6 +67,15 @@ android { } } } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } } dependencies { @@ -82,26 +96,35 @@ dependencies { * Ref: https://stackoverflow.com/a/70870040/6927433 */ implementation(BuildSystem.libraries.androidXWorkRuntime) - // Hyperion debugger - debugImplementation(BuildSystem.libraries.hyperionCore) - debugImplementation(BuildSystem.libraries.hyperionSharedPreferences) - releaseImplementation(BuildSystem.libraries.hyperionNoop) + // Swrve implementation(BuildSystem.libraries.swrve) implementation(BuildSystem.libraries.swrveGeo) - implementation(BuildSystem.libraries.teavaroSDK) implementation(BuildSystem.libraries.googleServices) + //FunnelConnect and UTIQ + implementation("com.github.Teavaro.FunnelConnect-Mobile-SDK:funnelConnect:0.1.41") + { + exclude("com.github.Teavaro.FunnelConnect-Mobile-SDK", "core-android") + } + implementation("com.github.Utiq-tech.UTIQ-Mobile-SDK:utiq:0.1.55") // - implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1") - implementation("androidx.navigation:navigation-fragment-ktx:2.3.5") - implementation("androidx.navigation:navigation-ui-ktx:2.3.5") - implementation ("com.google.code.gson:gson:2.8.2") - - testImplementation("junit:junit:4.13.2") + val lifecycleVersion = "2.8.3" + val navigationVersion = "2.7.7" + implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion") + implementation("androidx.navigation:navigation-fragment-ktx:$navigationVersion") + implementation("androidx.navigation:navigation-ui-ktx:$navigationVersion") + implementation ("com.google.code.gson:gson:2.10.1") - val room_version = "2.3.0" // check latest version from docs + // Hyperion debugger + //debugImplementation(BuildSystem.libraries.hyperionCore) + //debugImplementation(BuildSystem.libraries.hyperionSharedPreferences) + //releaseImplementation(BuildSystem.libraries.hyperionNoop) - implementation("androidx.room:room-runtime:$room_version") - annotationProcessor("androidx.room:room-compiler:$room_version") -} \ No newline at end of file + testImplementation("junit:junit:4.13.2") + //Room + val roomVersion = "2.6.1" + implementation("androidx.room:room-runtime:$roomVersion") + annotationProcessor("androidx.room:room-compiler:$roomVersion") + kapt("androidx.room:room-compiler:$roomVersion") + } \ No newline at end of file diff --git a/app/src/androidTest/java/com/teavaro/ecommDemoApp/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/teavaro/ecommDemoApp/ExampleInstrumentedTest.kt index 23695a2..28f9546 100644 --- a/app/src/androidTest/java/com/teavaro/ecommDemoApp/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/teavaro/ecommDemoApp/ExampleInstrumentedTest.kt @@ -1,24 +1,24 @@ package com.teavaro.ecommDemoApp -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.teavaro.teavarodemoapp", appContext.packageName) - } -} \ No newline at end of file +//import androidx.test.platform.app.InstrumentationRegistry +//import androidx.test.ext.junit.runners.AndroidJUnit4 +// +//import org.junit.Test +//import org.junit.runner.RunWith +// +//import org.junit.Assert.* +// +///** +// * Instrumented test, which will execute on an Android device. +// * +// * See [testing documentation](http://d.android.com/tools/testing). +// */ +//@RunWith(AndroidJUnit4::class) +//class ExampleInstrumentedTest { +// @Test +// fun useAppContext() { +// // Context of the app under test. +// val appContext = InstrumentationRegistry.getInstrumentation().targetContext +// assertEquals("com.teavaro.teavarodemoapp", appContext.packageName) +// } +//} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1df6569..e4cf295 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,22 +1,23 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.teavaro.ecommDemoApp"> + - + - @@ -30,7 +31,16 @@ + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/app_icon-playstore.png b/app/src/main/app_icon-playstore.png new file mode 100644 index 0000000..0b0a368 Binary files /dev/null and b/app/src/main/app_icon-playstore.png differ diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/MyBroadcastReceiver.java b/app/src/main/java/com/teavaro/ecommDemoApp/MyBroadcastReceiver.java new file mode 100644 index 0000000..dd03c87 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/MyBroadcastReceiver.java @@ -0,0 +1,15 @@ +package com.teavaro.ecommDemoApp; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +public class MyBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + // Handle the broadcast event + Log.d("MyBroadcastReceiver", "Broadcast received"); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/Item.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/Item.kt deleted file mode 100644 index c9e891a..0000000 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/Item.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.teavaro.ecommDemoApp.core - -data class Item ( - var id: Int, - var title: String, - var description: String, - var price: Float, - var picture: String, - var isOffer: Boolean = false, - var isInStock: Boolean = true, - var isWish: Boolean = false, - var countOnCart: Int = 0 -) \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/LogInMenu.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/LogInMenu.kt deleted file mode 100644 index 0d8f3e1..0000000 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/LogInMenu.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.teavaro.ecommDemoApp.core - -import android.view.Menu - -object LogInMenu { - lateinit var menu: Menu -} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/PushNotification.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/PushNotification.kt deleted file mode 100644 index 231cad3..0000000 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/PushNotification.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.teavaro.ecommDemoApp.core - -import java.io.BufferedInputStream -import java.io.InputStream -import java.net.HttpURLConnection -import java.net.URL - -object PushNotification { - - private const val swrveKeyCampaign = "708f47c5-e22d-457b-9d34-4cd35a160acb" - private const val URL = "https://service.swrve.com/push?push_key=$swrveKeyCampaign" - - fun send(user: String?, message: String?): String { - return try { - if(user != null && message != null) { - val url = URL("$URL&user=$user") - val urlConnection: HttpURLConnection = url.openConnection() as HttpURLConnection - urlConnection.requestMethod = "POST" - try { - val response: InputStream = BufferedInputStream(urlConnection.inputStream) - response.toString() - } finally { - urlConnection.disconnect() - } - } - else - "" - } catch (e: java.lang.Exception){ - "DemoApp: $e" - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/SharedPreferenceUtils.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/SharedPreferenceUtils.kt deleted file mode 100644 index 1455f82..0000000 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/SharedPreferenceUtils.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.teavaro.ecommDemoApp.core - -import android.content.Context - -object SharedPreferenceUtils { - - private const val STUB_MODE = "STUB_MODE" - - private fun getSharedPreferences(context: Context) = context.getSharedPreferences("MySharedPreferences", Context.MODE_PRIVATE) - - fun isStubMode(context: Context) = this.getSharedPreferences(context).getBoolean(STUB_MODE, false) - - fun setStubMode(context: Context, value: Boolean) { - this.getSharedPreferences(context).edit().putBoolean(STUB_MODE, value).apply() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/Store.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/Store.kt index 3e7ddba..4161edb 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/Store.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/Store.kt @@ -1,66 +1,120 @@ package com.teavaro.ecommDemoApp.core +import android.annotation.SuppressLint +import android.app.Activity import android.content.Context +import android.content.Intent +import android.net.Uri import android.util.Log +import android.webkit.WebView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentManager import com.google.gson.Gson -import com.teavaro.ecommDemoApp.ui.PermissionConsentDialogFragment -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import com.teavaro.funnelConnect.utils.platformTypes.permissionsMap.PermissionsMap +import com.google.gson.reflect.TypeToken +import com.swrve.sdk.SwrveSDK +import com.swrve.sdk.geo.SwrveGeoSDK +import com.teavaro.ecommDemoApp.R +import com.teavaro.ecommDemoApp.core.dataClases.InfoResponse +import com.teavaro.ecommDemoApp.core.room.ACEntity +import com.teavaro.ecommDemoApp.core.room.AppDb +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.SharedPreferenceUtils +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.ui.AbandonedCartDialogFragment +import com.teavaro.ecommDemoApp.ui.ItemDescriptionDialogFragment +import com.teavaro.ecommDemoApp.ui.permissions.PermissionConsentDialogFragment +import com.teavaro.ecommDemoApp.ui.permissions.UtiqConsent +import com.teavaro.funnelConnect.main.FunnelConnectSDK +import com.teavaro.funnelConnect.utils.platformTypes.permissionsMap.Permissions +import com.utiq.utiqTech.main.Utiq +import org.json.JSONObject +import java.lang.reflect.Type +import java.net.URLEncoder + +@SuppressLint("StaticFieldLeak") object Store { - private var listItems: ArrayList = ArrayList() - var section = "" - var isLogin = false - var infoResponse: String = "{}" - val notificationName = "APP_CS" - val notificationVersion = 4 - var description = "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don’t look even slightly believable. If you are going to use a passage of Lorem Ipsum." - - init { - listItems.add(Item(0, "Jacob’s Baked Crinklys Cheese", description,60.00f, "crinklys", true)) - listItems.add(Item(1, "Pork Cocktail Sausages, Pack", description, 54.00f, "pork", true, false)) - listItems.add(Item(2, "Broccoli and Cauliflower Mix", description, 6.00f, "cauliflower")) - listItems.add(Item(3, "Morrisons Creamed Rice Pudding", description, 44.00f, "paprika")) - listItems.add(Item(4, "Fresh For The Bold Ground Amazon", description, 12.00f, "burst")) - listItems.add(Item(5, "Frito-Lay Doritos & Cheetos Mix", description, 20.00f, "watermelon")) - listItems.add(Item(6, "Green Mountain Coffee Roast", description, 20.00f, "grapes")) - listItems.add(Item(7, "Nature’s Bakery Whole Wheat Bars", description, 50.00f, "mixed")) - } + val stubToken = "523393b9b7aa92a534db512af83084506d89e965b95c36f982200e76afcb82cb" + private var db: AppDb? = null + var listItems: ArrayList = ArrayList() + var listOffers: ArrayList = ArrayList() + var listCart: ArrayList = ArrayList() + var listWish: ArrayList = ArrayList() + var listAc: ArrayList = ArrayList() + var section = "none" + var webView: WebView? = null + var navigateAction: ((Int) -> Unit)? = null + var infoResponse: String? = null + var attributes: String? = null + val keyOm = "CS-OM" + val keyOpt = "CS-OPT" + val keyNba = "CS-NBA" + val keyUtiq = "CS-UTIQ" + val fcNotificationsName = "MAIN_CS" + val utiqNotificationsName = "UTIQ_CS" + val notificationsVersion = 1 + val userType = "enemail" + var atid: String = "UTIQ not initialized." + var mtid: String = "UTIQ not initialized." + var umid: String? = "FunnelConnect not initialized." + var userId: String? = null + var itemId = "" + var isFunnelConnectStarted = false + var description = + "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don’t look even slightly believable. If you are going to use a passage of Lorem Ipsum." + var refreshCeltraAd: (() -> Unit)? = null fun addItemToCart(id: Int) { - listItems[id].countOnCart += 1 + listItems[id].countInCart += 1 + updateItemDB(listItems[id]) + listCart = getItemsCart() } fun removeItemFromCart(id: Int) { - listItems[id].countOnCart = 0 + listItems[id].countInCart = 0 + updateItemDB(listItems[id]) + listCart = getItemsCart() + } + + fun updateItemDB(item: ItemEntity) { + db?.let { + Thread { + it.itemDao().update(item) + }.start() + } } fun addItemToWish(id: Int) { - listItems[id].isWish = true + listItems[id].isInWish = true + updateItemDB(listItems[id]) + listWish = getItemsWish() } fun removeItemFromWish(id: Int) { - listItems[id].isWish = false + listItems[id].isInWish = false + updateItemDB(listItems[id]) + listWish = getItemsWish() } - fun getItems(): ArrayList { + fun getItems(): ArrayList { return listItems } - fun getItemsCart(): ArrayList { - val listCart = ArrayList() + fun getItemsCart(): ArrayList { + val listCart = ArrayList() for (item in listItems) { - if (item.countOnCart > 0) + if (item.countInCart > 0) { listCart.add(item) + } } return listCart } - fun getItemsWish(): ArrayList { - val listWish = ArrayList() + fun getItemsWish(): ArrayList { + val listWish = ArrayList() for (item in listItems) { - if (item.isWish) + if (item.isInWish) listWish.add(item) } return listWish @@ -69,13 +123,13 @@ object Store { fun getTotalPriceCart(): Float { var total = 0f for (item in listItems) { - total += item.price * item.countOnCart + total += item.price * item.countInCart } return total } - fun getItemsOffer(): ArrayList { - val listOffer = ArrayList() + fun getItemsOffer(): ArrayList { + val listOffer = ArrayList() for (item in listItems) { if (item.isOffer) listOffer.add(item) @@ -85,75 +139,502 @@ object Store { fun removeAllCartItems() { for (item in listItems) { - item.countOnCart = 0 + if (item.countInCart > 0) { + item.countInCart = 0 + updateItemDB(item) + } } } - fun showPermissionsDialog(context: Context, supportFragmentManager: FragmentManager) { + fun showPermissionsDialog(context: Activity, supportFragmentManager: FragmentManager) { PermissionConsentDialogFragment.open( supportFragmentManager, { omPermissionAccepted, optPermissionAccepted, nbaPermissionAccepted -> - val permissions = PermissionsMap() - permissions.addPermission("CS-TMI",omPermissionAccepted) - permissions.addPermission("CS-OPT",optPermissionAccepted) - permissions.addPermission("CS-NBA",nbaPermissionAccepted) - FunnelConnectSDK.cdp().updatePermissions(permissions, notificationName,notificationVersion) - if(nbaPermissionAccepted) { - FunnelConnectSDK.trustPid().acceptConsent() - val isStub = SharedPreferenceUtils.isStubMode(context) - FunnelConnectSDK.trustPid().startService(isStub) + updatePermissions( + omPermissionAccepted, + optPermissionAccepted, + nbaPermissionAccepted, + context + ) + if (omPermissionAccepted || optPermissionAccepted || nbaPermissionAccepted) { + val stubToken = SharedPreferenceUtils.getStubToken(context) + Utiq.checkMNOEligibility(stubToken, { + showUtiqConsent(context, supportFragmentManager) + }, { + + }) + } else { + clearData(context) } - else - FunnelConnectSDK.trustPid().rejectConsent() }, { - FunnelConnectSDK.trustPid().rejectConsent() - val permissions = PermissionsMap() - permissions.addPermission("CS-TMI",false) - permissions.addPermission("CS-OPT",false) - permissions.addPermission("CS-NBA",false) - FunnelConnectSDK.cdp().updatePermissions(permissions, notificationName,notificationVersion) + updatePermissions( + om = false, + opt = false, + nba = false, + context + ) + clearData(context) }) } - fun getBanner(): String{ - var text = "" - var gson = Gson() - var obj: InfoResponse = gson.fromJson(infoResponse, InfoResponse::class.java) - obj?.let { ob -> - ob.attributes?.let { attr -> - attr.forEach { - text += "&" + it.key + "=" + it.value + fun showUtiqConsent(context: Activity, supportFragmentManager: FragmentManager) { + UtiqConsent.open(supportFragmentManager) { consent -> + if (Utiq.isInitialized()) { + if (consent) { + Utiq.acceptConsent() + utiqStartService(context) + } else { + Utiq.rejectConsent() + } + updateUtiqConsent(consent, context) + } + } + } + + private fun updateUtiqConsent( + consent: Boolean, + context: Activity + ) { + val action = { + val permissions = Permissions() + permissions.addPermission(keyUtiq, consent) + FunnelConnectSDK.updatePermissions( + permissions, + utiqNotificationsName, + notificationsVersion, { + updateFCData(it) + } + ) + } + if (isFunnelConnectStarted) { + action.invoke() + } else { + fcStartService(context) { + action.invoke() + } + } + } + + fun updatePermissions( + om: Boolean, + opt: Boolean, + nba: Boolean, + context: Activity + ) { + val action = { + val permissions = Permissions() + permissions.addPermission(keyOm, om) + permissions.addPermission(keyOpt, opt) + permissions.addPermission(keyNba, nba) + FunnelConnectSDK.updatePermissions( + permissions, + fcNotificationsName, + notificationsVersion, { + updateFCData(it) + } + ) + } + if (isFunnelConnectStarted) { + action.invoke() + } else { + fcStartService(context) { + action.invoke() + } + } + } + + fun showAbandonedCartDialog(supportFragmentManager: FragmentManager, items: List) { + AbandonedCartDialogFragment.open( + supportFragmentManager, + items + ) { + it.forEach { item -> + addItemToCart(item.itemId) + } + navigateAction?.invoke(R.id.navigation_cart) + } + } + + fun getAttributesFromInfo(): String? { + infoResponse?.let { info -> + var gson = Gson() + val classOb = InfoResponse::class.java + classOb?.let { classOnj -> + var obj: InfoResponse? = gson.fromJson(info, classOnj) + obj?.let { ob -> + ob.attributes?.let { attr -> + val gsonType: Type = object : TypeToken?>() {}.type + return gson.toJson(attr, gsonType) + } } } } - Log.d("iran:infoResponse", infoResponse) - Log.d("iran:attr", text) + return null + } + + fun getBanner(): String { + var text = "&attributes=${URLEncoder.encode("{}", "utf-8")}" + if (isNbaPermissionAccepted()) { + attributes?.let { + text = "&attributes=${URLEncoder.encode(it, "utf-8")}" + } + text += "&allowTracking=true" + } else { + text += "&allowTracking=false" + } return """ -
- -
+
+ +
- + """.trimIndent() } -} \ No newline at end of file + + fun initializeData(context: Context, db: AppDb, action: ((Int) -> Unit)) { + navigateAction = action + this.db = db + Thread { +// db.itemDao().removeAllItems() +// db.acDao().removeAllAc() + if (db.itemDao().getAllItems().isEmpty()) { + db.itemDao().saveItems( + ItemEntity( + 0, + "RUF Porridge Apfel Zimt mit Vollkorn Haferflocken", + description, + 1.69f, + "porridge", + "/product/ruf-porridge-apfel-zimt-mit-vollkorn-haferflocken/", + true + ) + ) + db.itemDao().saveItems( + ItemEntity( + 1, + "TSARINE Caviar 50g", + description, + 45.50f, + "tsarine", + "/product/marke-tsarine-caviar-50g/", + true, + acId = 123 + ) + ) + db.itemDao().saveItems( + ItemEntity( + 2, + "Hillshire Farm Lit'l Smokies Salchicha ahumada, 14 oz", + description, + 5.31f, + "hillshire", + "/product/hillshire-farm-litl-smokies-salchicha-ahumada-14-oz/" + ) + ) + db.itemDao().saveItems( + ItemEntity( + 3, + "Good Soy Cookies", + description, + 3.99f, + "cookies", + "/product/good-soy-cookies/" + ) + ) + db.itemDao().saveItems( + ItemEntity( + 4, + "Jack Link’s Teriyaki, Beef Jerky", + description, + 6.60f, + "teriyaki", + "/product/save-on-jack-links-beef-jerky-teriyaki/" + ) + ) + db.itemDao().saveItems( + ItemEntity( + 5, + "Absolute Organic Cashews", + description, + 20.00f, + "cashews", + "/product/healthy-snack-box-variety-pack-60-count/" + ) + ) + db.itemDao().saveItems( + ItemEntity( + 6, + "Pork Cocktail Sausages, Pack", + description, + 3.29f, + "pork", + "/product/pork-cocktail-sausages-pack/" + ) + ) + } + listItems = db.itemDao().getAllItems() as ArrayList + this.listAc = db.acDao().getAllAcs() as ArrayList + listOffers = getItemsOffer() + action.invoke(R.id.navigation_home) + userId = SharedPreferenceUtils.getUserId(context) + }.start() + } + + fun processCelraAction( + context: Context, + data: String, + supportFragmentManager: FragmentManager + ) { + var obj = JSONObject(data) + obj?.let { ob -> + ob.getJSONObject("attributes")?.let { attr -> + if (!attr.isNull("impression")) { + attr.getString("impression")?.let { impression -> + if (impression == "ShopView") { + section = "ShopView" + navigateAction?.let { + it.invoke(R.id.navigation_shop) + } + } + if (impression == "AbCartView" && listAc.isEmpty()) { + Toast.makeText( + context, + "There isn't abandoned items.", + Toast.LENGTH_LONG + ).show() + } + } + } + if (!attr.isNull("item_id")) { + attr.getString("item_id")?.let { + ItemDescriptionDialogFragment.open( + supportFragmentManager, + listItems[it.toInt()], + { + addItemToCart(it.toInt()) + }, + { + addItemToWish(it.toInt()) + }) + } + } + if (!attr.isNull("item_data")) { + attr.getString("item_data")?.let { data -> + Log.d("OkHttp", data) + findItemWithData(data)?.let { + ItemDescriptionDialogFragment.open( + supportFragmentManager, + it, + { + addItemToCart(it.itemId) + }, + { + addItemToWish(it.itemId) + }) + + } + } + } + if (!attr.isNull("ab_cart_id")) { + attr.getString("ab_cart_id")?.let { + if (it != "-1") { + refreshAcItems(it.toInt()) { list -> + showAbandonedCartDialog(supportFragmentManager, list) + } + } + } + } + if (!attr.isNull("ident_url")) { + attr.getString("ident_url")?.let { url -> + if (userId != null) { + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + context.startActivity(browserIntent) + } else + Toast.makeText(context, "Log in first please.", Toast.LENGTH_LONG) + .show() + } + } + } + } + } + + private fun findItemWithData(data: String): ItemEntity? { + var index: Int + for (item in listItems) { + index = item.data.indexOf(data) + if (index > -1) { + return item + } + } + return null + } + + fun addAbandonedCart(items: List): Int { + val acId = getUniqueId() + db?.let { db -> + Thread { + for (item in items) { + item.acId = acId + db.itemDao().update(item) + } + ACEntity(acId).let { + db.acDao().saveAC(it) + this.listAc.add(it) + } + }.start() + } + return acId + } + + fun getUniqueId(): Int { + return (0..1000).random() + } + + fun refreshAcItems(acId: Int, action: ((List) -> Unit)) { + db?.let { + Thread { + val list = it.itemDao().getAllAcItems(acId) + action.invoke(list) + }.start() + } + } + + fun handleDeepLink( + context: Context, + appLinkData: Uri, + supportFragmentManager: FragmentManager + ) { + val acId = appLinkData.getQueryParameter("ab_cart_id") + val itemId = appLinkData.getQueryParameter("item_id") + val impression = appLinkData.getQueryParameter("impression") + acId?.let { + refreshAcItems(it.toInt()) { items -> + showAbandonedCartDialog(supportFragmentManager, items) + } + navigateAction?.invoke(R.id.navigation_home) + } + itemId?.let { + ItemDescriptionDialogFragment.open( + (context as AppCompatActivity).supportFragmentManager, + listItems[it.toInt()], + { + addItemToCart(it.toInt()) + }, + { + addItemToWish(it.toInt()) + }) + navigateAction?.invoke(R.id.navigation_home) + } + impression?.let { + if (it == "ShopView") { + navigateAction?.invoke(R.id.navigation_shop) + } + } + } + + fun getAbCartId(): Int? { + if (this.listAc.isNotEmpty()) { +// Log.d("iraniranCountAc", this.listAc.size.toString()) + return this.listAc.last().acId + } + return null + } + + + fun utiqStartService(context: Context) { + atid = "{\"status\":\"notFound\"}" + mtid = "{\"status\":\"notFound\"}" + val stubToken = SharedPreferenceUtils.getStubToken(context) + Utiq.startService(stubToken, { + Log.d("okhttp.OkHttpClient", "startService good") + atid = it.atid.toString() + mtid = it.mtid.toString() + TrackUtils.mtid = mtid + }, { + Log.d("okhttp.OkHttpClient", it.message) + }) + } + + fun getClickIdentLink(context: Context): String? { + SharedPreferenceUtils.getUserId(context)?.let { + return "https://funnelconnect.brand-demo.com/op/brand-demo-app-click-ident/click?$userType=$userId&uri=https%3A%2F%2Fweb.brand-demo.com%2F" + } + return null + } + + fun clearData(context: Context) { + umid = "" + infoResponse = "" + attributes = "" + userId = null + listAc.clear() + SharedPreferenceUtils.setUserId(context, null) + SharedPreferenceUtils.setLogin(context, false) + FunnelConnectSDK.clearData() + FunnelConnectSDK.clearCookies() + clearUtiqData(context) + isFunnelConnectStarted = false + } + + fun clearUtiqData(context: Context) { + SharedPreferenceUtils.setStubToken(context, null) + Utiq.clearData() + Utiq.clearCookies() + atid = "" + mtid = "" + TrackUtils.mtid = null + } + + fun isNbaPermissionAccepted(): Boolean { + return FunnelConnectSDK.getPermissions().getPermission(keyNba) + } + + fun isOptPermissionAccepted(): Boolean { + return FunnelConnectSDK.getPermissions().getPermission(keyOpt) + } + + fun fcStartService( + context: Activity, + action: (() -> Unit)? = null + ) { + FunnelConnectSDK + .startService(null, fcNotificationsName, notificationsVersion, { + updateFCData(it) + SwrveSDK.start(context, FunnelConnectSDK.getUMID()) + SwrveGeoSDK.start(context) + isFunnelConnectStarted = true + action?.invoke() + }, + { + Log.d("error:", "FunnelConnectSDK.startService") + }) + } + + fun updateFCData(info: String) { + infoResponse = info + attributes = getAttributesFromInfo() + umid = FunnelConnectSDK.getUMID() + refreshCeltraAd?.invoke() + } +} + diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/StringUtils.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/StringUtils.kt deleted file mode 100644 index eef8827..0000000 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/StringUtils.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.teavaro.ecommDemoApp.core - -import com.teavaro.funnelConnect.utils.stringUtils.IStringUtils -import java.net.URLDecoder -import java.nio.charset.StandardCharsets -import java.security.MessageDigest - -internal object StringUtils: IStringUtils { - - fun stringToSha256String(string: String): String { - val bytes = MessageDigest.getInstance("SHA-256").digest(string.encodeToByteArray()) - return bytes.fold("") { str, it -> str + "%02x".format(it) } - } - - fun decodeURL(string: String): String { - return URLDecoder.decode(string, StandardCharsets.UTF_8.toString()) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/InfoResponse.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/dataClases/InfoResponse.kt similarity index 88% rename from app/src/main/java/com/teavaro/ecommDemoApp/core/InfoResponse.kt rename to app/src/main/java/com/teavaro/ecommDemoApp/core/dataClases/InfoResponse.kt index 88aecda..5c6a5bf 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/InfoResponse.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/dataClases/InfoResponse.kt @@ -1,4 +1,4 @@ -package com.teavaro.ecommDemoApp.core +package com.teavaro.ecommDemoApp.core.dataClases data class InfoResponse( val umid: String? = null, diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACEntity.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACEntity.kt new file mode 100644 index 0000000..2a72a20 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACEntity.kt @@ -0,0 +1,22 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +@Entity +data class ACEntity( + @SerializedName("ac_id") + @Expose + @ColumnInfo(name = "ac_id") + @PrimaryKey + var acId: Int = -1, +) + +@Entity(primaryKeys = ["ac_id", "item_id"]) +data class ACItemCrossRef( + val ac_id: Int, + val item_id: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACWithItems.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACWithItems.kt new file mode 100644 index 0000000..11a1999 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ACWithItems.kt @@ -0,0 +1,15 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.Embedded +import androidx.room.Junction +import androidx.room.Relation + +data class ACWithItems( + @Embedded val acEntity: ACEntity, + @Relation( + parentColumn = "ac_id", + entityColumn = "item_id", + associateBy = Junction(ACItemCrossRef::class) + ) + var items: List +) diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AcDAO.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AcDAO.kt new file mode 100644 index 0000000..53b6c93 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AcDAO.kt @@ -0,0 +1,22 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Transaction + +@Dao +interface AcDAO { + @Transaction + @Query("SELECT * FROM ACEntity") + fun getACWithItems(): List + + @Insert + fun saveAC(ac: ACEntity) + + @Query("SELECT * FROM ACEntity") + fun getAllAcs(): List + + @Query("Delete from ACEntity") + fun removeAllAc() +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AppDb.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AppDb.kt new file mode 100644 index 0000000..aa74604 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/AppDb.kt @@ -0,0 +1,12 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.Database +import androidx.room.RoomDatabase + +@Database(entities = [(ItemEntity::class),(ACEntity::class), (ACItemCrossRef::class)], + version = 15) +abstract class AppDb : RoomDatabase() { + + abstract fun itemDao(): ItemDAO + abstract fun acDao(): AcDAO +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemDAO.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemDAO.kt new file mode 100644 index 0000000..c24fcca --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemDAO.kt @@ -0,0 +1,30 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.* + +@Dao +interface ItemDAO { + + @Insert + fun saveItems(item: ItemEntity) + + @Query(value = "Select * from ItemEntity") + fun getAllItems(): List + + @Query(value = "Select * from ItemEntity WHERE ac_id = :acId") + fun getAllAcItems(acId: Int): List + + @Query("Delete from ItemEntity") + fun removeAllItems() + + @Query("Update ItemEntity SET count_in_cart=:countInCart WHERE item_id = :itemId") + fun addItemToCart(itemId: Int, countInCart: Int) + + @Update + fun update(item: ItemEntity) + + @Delete + fun delete(item: ItemEntity) + + +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemEntity.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemEntity.kt new file mode 100644 index 0000000..e3459fd --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/room/ItemEntity.kt @@ -0,0 +1,62 @@ +package com.teavaro.ecommDemoApp.core.room + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +@Entity +class ItemEntity( + + @SerializedName("item_id") + @Expose + @ColumnInfo(name = "item_id") + @PrimaryKey + var itemId: Int = 0, + + @SerializedName("title") + @Expose + var title: String = "", + + @SerializedName("desc") + @Expose + var desc: String = "", + + @SerializedName("price") + @Expose + var price: Float = 0f, + + @SerializedName("picture") + @Expose + var picture: String = "", + + @SerializedName("data") + @Expose + var data: String = "", + + @SerializedName("is_offer") + @ColumnInfo(name = "is_offer") + @Expose + var isOffer: Boolean = false, + + @SerializedName("is_in_stock") + @ColumnInfo(name = "is_in_stock") + @Expose + var isInStock: Boolean = true, + + @SerializedName("is_in_wish") + @ColumnInfo(name = "is_in_wish") + @Expose + var isInWish: Boolean = false, + + @SerializedName("count_in_cart") + @ColumnInfo(name = "count_in_cart") + @Expose + var countInCart: Int = 0, + + @SerializedName("ac_id") + @ColumnInfo(name = "ac_id") + @Expose + var acId: Int? = null, +) \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/HTTPAsyncTask.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/HTTPAsyncTask.kt similarity index 74% rename from app/src/main/java/com/teavaro/ecommDemoApp/core/HTTPAsyncTask.kt rename to app/src/main/java/com/teavaro/ecommDemoApp/core/utils/HTTPAsyncTask.kt index f02340f..843d014 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/core/HTTPAsyncTask.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/HTTPAsyncTask.kt @@ -1,10 +1,11 @@ -package com.teavaro.ecommDemoApp.core +package com.teavaro.ecommDemoApp.core.utils import android.os.AsyncTask class HTTPAsyncTask(private val action: (()->Unit)) : AsyncTask() { override fun doInBackground(vararg items: String?): String { - return PushNotification.send(items[0], items[1]) + action.invoke() + return "" } override fun onPostExecute(result: String?) { action.invoke() diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/PushNotification.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/PushNotification.kt new file mode 100644 index 0000000..8eac423 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/PushNotification.kt @@ -0,0 +1,61 @@ +package com.teavaro.ecommDemoApp.core.utils + +import com.teavaro.ecommDemoApp.core.Store +import java.io.BufferedInputStream +import java.io.InputStream +import java.net.HttpURLConnection +import java.net.URL + +object PushNotification { + + private const val shopKeyCampaign = "708f47c5-e22d-457b-9d34-4cd35a160acb" + private const val cashewsKeyCampaign = "27e0048f-1200-44be-b3e1-fed6eecd437a" + private const val acKeyCampaign = "cf0d9bc0-cf5e-4687-b5d2-c75d0ddc8245" + private const val identClickKeyCampaign = "47399c46-d27c-4679-97b8-70e0bc5dc91d" + private const val URL = "https://service.swrve.com/push" + + fun send(address: String, action: (()->Unit)) { + return background{ + try { + val url = URL(address) + val urlConnection: HttpURLConnection = url.openConnection() as HttpURLConnection + urlConnection.requestMethod = "POST" + try { + val response: InputStream = BufferedInputStream(urlConnection.inputStream) + response.toString() + action.invoke() + } finally { + urlConnection.disconnect() + } + } catch (e: java.lang.Exception){ + "Response:$e" + } + } + } + + fun sendCashews(user: String, action: (()->Unit)) { + send("$URL?push_key=$cashewsKeyCampaign&user=$user&data_template={\"item_id\":\"5\"}", action) + } + + fun sendAbandonedCart(user: String, action: (()->Unit)) { + Store.getAbCartId()?.let { + send("$URL?push_key=$acKeyCampaign&user=$user&data_template={\"ab_cart_id\":\"$it\"}", action) + } + } + + fun sendIdentClick(user: String, action: (()->Unit)) { + Store.userId?.let { + send("$URL?push_key=$identClickKeyCampaign&user=$user&data_template={\"userr_id\":\"$it\"}", action) + } + } + + fun sendShop(user: String, action: (()->Unit)) { + send("$URL?push_key=$shopKeyCampaign&user=$user", action) + } + + fun background(action: () -> Unit){ + Thread{ + action.invoke() + }.start() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/SharedPreferenceUtils.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/SharedPreferenceUtils.kt new file mode 100644 index 0000000..a79e68f --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/SharedPreferenceUtils.kt @@ -0,0 +1,34 @@ +package com.teavaro.ecommDemoApp.core.utils + +import android.content.Context + +object SharedPreferenceUtils { + + private const val STUB_TOKEN = "STUB_TOKEN" + private const val IS_LOGIN = "IS_LOGIN" + private const val USER_ID = "USER_ID" + + private fun getSharedPreferences(context: Context) = context.getSharedPreferences("MySharedPreferences", Context.MODE_PRIVATE) + + fun getStubToken(context: Context) = getSharedPreferences(context).getString(STUB_TOKEN, null) + + fun setStubToken(context: Context, value: String?) { + getSharedPreferences(context).edit().putString(STUB_TOKEN, value).apply() + } + + fun isLogin(context: Context) = getSharedPreferences(context).getBoolean(IS_LOGIN, false) + + fun setLogin(context: Context, value: Boolean) { + getSharedPreferences(context).edit().putBoolean(IS_LOGIN, value).apply() + } + + fun clearPreferences(context: Context){ + getSharedPreferences(context).edit().clear() + } + + fun setUserId(context: Context, value: String?) { + getSharedPreferences(context).edit().putString(USER_ID, value).apply() + } + + fun getUserId(context: Context) = getSharedPreferences(context).getString(USER_ID, null) +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/StringUtils.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/StringUtils.kt new file mode 100644 index 0000000..7b3777a --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/StringUtils.kt @@ -0,0 +1,34 @@ +package com.teavaro.ecommDemoApp.core.utils + +import android.content.ClipData +import android.content.Context +import android.os.Build +import android.text.ClipboardManager +import java.net.URLDecoder +import java.nio.charset.StandardCharsets +import java.security.MessageDigest +import java.util.Base64 + +internal object StringUtils { + + fun stringToSha256String(string: String): String { + val bytes = MessageDigest.getInstance("SHA-256").digest(string.encodeToByteArray()) + return bytes.fold("") { str, it -> str + "%02x".format(it) } + } + + fun decodeURL(string: String): String { + return URLDecoder.decode(string, StandardCharsets.UTF_8.toString()) + } + + fun setClipboard(context: Context, text: String) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboard.text = text + } else { + val clipboard = + context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager + val clip = ClipData.newPlainText("Copied Text", text) + clipboard.setPrimaryClip(clip) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/TrackUtils.kt b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/TrackUtils.kt new file mode 100644 index 0000000..65296ac --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/core/utils/TrackUtils.kt @@ -0,0 +1,62 @@ +package com.teavaro.ecommDemoApp.core.utils + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.funnelConnect.main.FunnelConnectSDK + +object TrackUtils : LifecycleObserver { + var mtid: String? = null + const val EVENT_NAME = "event_name" + const val EVENT_DATA = "event_data" + + fun impression(value: String) { + event(value, "navigation") + } + + fun click(value: String){ + event(value, "click") + } + + fun event(value: String, name: String){ + val eventsMap = mutableMapOf( EVENT_NAME to name, EVENT_DATA to value) + mtid?.let { + eventsMap["mtid"] = it + } + events(eventsMap) + } + + fun events(events: Map){ + if(FunnelConnectSDK.isInitialized() && Store.isOptPermissionAccepted()) { + FunnelConnectSDK.logEvents(events) + } + } + + fun geoPlace(value: String){ + event(value, "location") + } + + fun lifeCycle(lifecycle: Lifecycle) { + lifecycle.addObserver(object: LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + when (event) { + Lifecycle.Event.ON_RESUME -> { + impression("on_resume_scene") + } + Lifecycle.Event.ON_PAUSE -> { + impression("on_pause_scene") + } + Lifecycle.Event.ON_CREATE -> { + impression("on_create_scene") + } + Lifecycle.Event.ON_DESTROY -> { + impression("on_destroy_scene") + } + else -> { } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/AbandonedCartDialogFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/AbandonedCartDialogFragment.kt new file mode 100644 index 0000000..6e72d0d --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/AbandonedCartDialogFragment.kt @@ -0,0 +1,80 @@ +package com.teavaro.ecommDemoApp.ui + +import android.app.Dialog +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.widget.TextView +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import com.teavaro.ecommDemoApp.R +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.FragmentAbandonedCartDialogBinding +import com.teavaro.ecommDemoApp.ui.shop.ShopAdapter + +class AbandonedCartDialogFragment(private var items: List) : DialogFragment(R.layout.fragment_abandoned_cart_dialog) { + + private var _binding: FragmentAbandonedCartDialogBinding? = null + private val binding get() = _binding!! + private var addItemsAction: ((List) -> Unit)? = null + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + TrackUtils.impression("abandoned_cart_view") + val dialog = super.onCreateDialog(savedInstanceState) + dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) + dialog.setCancelable(true) + dialog.setCanceledOnTouchOutside(true) + return dialog + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAbandonedCartDialogBinding.inflate(inflater, container, false) + val root: View = binding.root + + binding.btnClose.setOnClickListener { + this.dismiss() + } + + binding.btnAddItemsToCart.setOnClickListener { + addItemsAction?.let { + TrackUtils.click("add_abandoned_items_to_cart") + it.invoke(items) + } + this.dismiss() + } + + items.let { + val shopAdapter = ShopAdapter(requireContext(), it) + var textView = TextView(requireContext()) + for (pos in 0..it.lastIndex){ + textView.text = pos.toString() + binding.listItems.addView(shopAdapter.getView(pos, view, root as ViewGroup)) + } + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + companion object { + fun open( + fm: FragmentManager, + items: List, + addItemsAction: ((List) -> Unit) + ) { + val dialogFragment = AbandonedCartDialogFragment(items) + dialogFragment.addItemsAction = addItemsAction + dialogFragment.show(fm, null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/FCApplication.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/FCApplication.kt index 75d7648..c92dec5 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/FCApplication.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/FCApplication.kt @@ -18,18 +18,35 @@ import com.swrve.sdk.geo.SwrveGeoSDK import com.teavaro.ecommDemoApp.BuildConfig import com.teavaro.ecommDemoApp.R import com.teavaro.ecommDemoApp.core.Store -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import com.teavaro.funnelConnect.data.models.dataClasses.FCOptions - +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.funnelConnect.data.models.FCOptions +import com.teavaro.funnelConnect.main.FunnelConnectSDK +import com.utiq.utiqTech.data.models.UtiqOptions +import com.utiq.utiqTech.main.Utiq @Suppress("unused") class FCApplication: Application() { + companion object { + lateinit var instance: Context + } + override fun onCreate() { super.onCreate() + instance = this this.initAppPolices() println("Teavaro:------------------initializing FunnelConnectSDK-${BuildConfig.VERSION_NAME}-------------") - FunnelConnectSDK.initialize(this, "R&Ai^v>TfqCz4Y^HH2?3uk8j", FCOptions(true)) + var config = resources.openRawResource(R.raw.fc_configs) + .bufferedReader() + .use { it.readText() } + val fcOptions = FCOptions().enableLogging().setFallBackConfigJson(config) + FunnelConnectSDK.initialize(this, "ko8G.Rv_vT97LiDuoBHbhBJt", fcOptions ) + config = resources.openRawResource(R.raw.utiq_configs) + .bufferedReader() + .use { it.readText() } + val utiqOptions = UtiqOptions().enableLogging().setFallBackConfigJson(config) + println("UTIQSDK-${BuildConfig.VERSION_NAME}-------------") + Utiq.initialize(this, "R&Ai^v>TfqCz4Y^HH2?3uk8j", utiqOptions) FirebaseApp.initializeApp(this) initSwrve() } @@ -54,9 +71,10 @@ class FCApplication: Application() { notificationManager.createNotificationChannel(channel); } } - val notificationConfig: SwrveNotificationConfig.Builder = SwrveNotificationConfig.Builder(R.drawable.burst, R.drawable.crinklys, channel) + val notificationConfig: SwrveNotificationConfig.Builder = SwrveNotificationConfig.Builder( + com.teavaro.ecommDemoApp.R.drawable.logo1, com.teavaro.ecommDemoApp.R.drawable.logo1, channel) .activityClass(MainActivity::class.java) - .largeIconDrawableId(R.drawable.grapes) + .largeIconDrawableId(com.teavaro.ecommDemoApp.R.drawable.logo1) .accentColorHex("#3949AB") config.notificationConfig = notificationConfig.build() config.notificationListener = SwrvePushNotificationListener { @@ -68,7 +86,7 @@ class FCApplication: Application() { //geo config val geoConfig = SwrveGeoConfig.Builder() .geofenceTransitionListener { name: String?, transition: String?, triggerLocation: Location?, customProperties: String? -> - FunnelConnectSDK.cdp().logEvent("entryGeoPlace", name.toString()) + TrackUtils.geoPlace(name.toString()) } .build() SwrveGeoSDK.init(this, geoConfig) diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/ItemDescriptionDialogFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/ItemDescriptionDialogFragment.kt index 571ec96..16fb3fc 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/ItemDescriptionDialogFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/ItemDescriptionDialogFragment.kt @@ -2,18 +2,19 @@ package com.teavaro.ecommDemoApp.ui import android.app.Dialog import android.os.Bundle +import android.util.Log import android.view.View import android.view.Window import android.widget.Button import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.Item +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentFItemDescriptionBinding import com.teavaro.ecommDemoApp.viewBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -class ItemDescriptionDialogFragment(item: Item) : +class ItemDescriptionDialogFragment(item: ItemEntity) : DialogFragment(R.layout.fragment_f_item_description) { private val binding by viewBinding(FragmentFItemDescriptionBinding::bind) @@ -24,7 +25,7 @@ class ItemDescriptionDialogFragment(item: Item) : // override fun getTheme() = R.style.FullScreenDimmedDialogFragment override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - FunnelConnectSDK.cdp().logEvent("Navigation", "itemDescriptionDialog") + TrackUtils.impression(item.data) val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) dialog.setCancelable(true) @@ -38,15 +39,17 @@ class ItemDescriptionDialogFragment(item: Item) : this.addToWishlistAction?.let { binding.btnAddToWish.visibility = Button.VISIBLE binding.btnAddToWish.setOnClickListener { + TrackUtils.click("add_to_wishlist" + "," + item.data) this.addToWishlistAction?.invoke() this.dismiss() } } this.addToCartAction?.let { - if(item.isInStock) { + if(item.isInStock == true) { binding.btnAddToCart.visibility = Button.VISIBLE binding.btnAddToCart.setOnClickListener { + TrackUtils.click("add_to_cart" + "," + item.data) this.addToCartAction?.invoke() this.dismiss() } @@ -60,7 +63,7 @@ class ItemDescriptionDialogFragment(item: Item) : private fun initialPresets() { binding.txtTitle.text = item.title - binding.txtDescription.text = item.description + binding.txtDescription.text = item.desc binding.txtPrice.text = "$" + item.price.toString() val imgId: Int = resources.getIdentifier(item.picture, "drawable", "com.teavaro.ecommDemoApp") @@ -71,10 +74,11 @@ class ItemDescriptionDialogFragment(item: Item) : fun open( fm: FragmentManager, - item: Item, + item: ItemEntity, addToCartAction: (() -> Unit)? = null, addToWishlistAction: (() -> Unit)? = null ) { + Log.d("OkHttp", "fun open(") val dialogFragment = ItemDescriptionDialogFragment(item) addToWishlistAction?.let { dialogFragment.addToWishlistAction = it } addToCartAction?.let { dialogFragment.addToCartAction = it } diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/MainActivity.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/MainActivity.kt index 120a507..eee9168 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/MainActivity.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/MainActivity.kt @@ -1,41 +1,61 @@ package com.teavaro.ecommDemoApp.ui +import android.content.Intent import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build import android.os.Bundle +import android.util.Log import android.view.Menu import android.view.MenuItem +import android.widget.Toast import android.widget.Toolbar +import androidx.annotation.RequiresApi import androidx.core.graphics.drawable.DrawableCompat import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController +import androidx.room.Room import com.google.android.material.bottomnavigation.BottomNavigationView -import com.swrve.sdk.SwrveSDK -import com.swrve.sdk.geo.SwrveGeoSDK import com.teavaro.ecommDemoApp.R import com.teavaro.ecommDemoApp.baseClasses.mvvm.BaseActivity -import com.teavaro.ecommDemoApp.core.* +import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.room.AppDb +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.ActivityMainBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK +import com.teavaro.funnelConnect.main.FunnelConnectSDK +import com.utiq.utiqTech.main.Utiq -class MainActivity: BaseActivity(ActivityMainBinding::inflate) { + +class MainActivity : BaseActivity(ActivityMainBinding::inflate) { private val navController by lazy { this.findNavController(R.id.nav_host_fragment_container) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(viewBinding.root) + + TrackUtils.lifeCycle(lifecycle) + + var db = Room.databaseBuilder(applicationContext, AppDb::class.java, "TeavaroEcommDB") + .fallbackToDestructiveMigration() + .build() + + + val navView: BottomNavigationView = viewBinding.navView - val appBarConfiguration = AppBarConfiguration(setOf( - R.id.navigation_home, - R.id.navigation_cart, - R.id.navigation_wishlist, - R.id.navigation_shop, - R.id.navigation_settings - ) + val appBarConfiguration = AppBarConfiguration( + setOf( + R.id.navigation_start, + R.id.navigation_home, + R.id.navigation_cart, + R.id.navigation_wishlist, + R.id.navigation_shop, + R.id.navigation_settings + ) ) setupActionBarWithNavController(this.navController, appBarConfiguration) navView.setupWithNavController(this.navController) @@ -45,27 +65,36 @@ class MainActivity: BaseActivity(ActivityMainBinding::infla supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); } - FunnelConnectSDK.onInitialize({ - if(FunnelConnectSDK.trustPid().isConsentAccepted()) { - val isStub = SharedPreferenceUtils.isStubMode(this) - FunnelConnectSDK.trustPid().startService(isStub) + Store.initializeData(this, db) { + this@MainActivity.runOnUiThread { + navView.selectedItemId = it + navController.navigate(it) } - FunnelConnectSDK.cdp().startService(null, Store.notificationName, Store.notificationVersion,{ - Store.infoResponse = it - if(FunnelConnectSDK.cdp().getPermissions().isEmpty()) + } + Log.d("okhttp.OkHttpClient:", "before UTIQ.onInitialize") + FunnelConnectSDK.onInitialize({ + Store.fcStartService(this){ + if (FunnelConnectSDK.getPermissions().isEmpty()) { Store.showPermissionsDialog(this, supportFragmentManager) - SwrveSDK.start(this, FunnelConnectSDK.cdp().getUmid()) - SwrveGeoSDK.start(this) - }, - { - }) + } + } }) { + Store.umid = "FunnelConnect failed initialization." + Toast.makeText(FCApplication.instance, it.message, Toast.LENGTH_LONG).show() } - - - + Utiq.onInitialize({ + Log.d("okhttp.OkHttpClient:", "inside UTIQ.onInitialize") + if (Utiq.isConsentAccepted()) { + Log.d("okhttp.OkHttpClient:", "isConsentAccepted()") + Store.utiqStartService(this) + } + }, { + Toast.makeText(FCApplication.instance, it.message, Toast.LENGTH_LONG).show() + }) + handleIntent(intent) } + @RequiresApi(Build.VERSION_CODES.M) fun setOverflowButtonColor(toolbar: Toolbar, color: Int) { var drawable: Drawable? = toolbar.overflowIcon if (drawable != null) { @@ -75,10 +104,21 @@ class MainActivity: BaseActivity(ActivityMainBinding::infla } } + private fun handleIntent(intent: Intent?) { + val appLinkAction: String? = intent?.action + val appLinkData: Uri? = intent?.data + showDeepLinkOffer(appLinkAction, appLinkData) + } + + private fun showDeepLinkOffer(appLinkAction: String?, appLinkData: Uri?) { + if (Intent.ACTION_VIEW == appLinkAction && appLinkData != null) { + Store.handleDeepLink(this, appLinkData, supportFragmentManager) + } + } + override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.login_menu, menu) - LogInMenu.menu = menu return true } @@ -86,20 +126,10 @@ class MainActivity: BaseActivity(ActivityMainBinding::infla // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. + Log.d("iraniran","navigation_home") when (item.itemId) { - else -> navController.navigate(R.id.navigation_settings) } return true } - - override fun onResume() { - super.onResume() - when(Store.section){ - "store" -> { - navController.navigate(R.id.navigation_shop) - Store.section = "" - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/StartFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/StartFragment.kt new file mode 100644 index 0000000..c29c3b3 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/StartFragment.kt @@ -0,0 +1,23 @@ +package com.teavaro.ecommDemoApp.ui + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.teavaro.ecommDemoApp.R + +class StartFragment : Fragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_start, container, false) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartAdapter.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartAdapter.kt index ab0a0aa..9a98452 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartAdapter.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartAdapter.kt @@ -1,5 +1,6 @@ package com.teavaro.ecommDemoApp.ui.cart +import android.annotation.SuppressLint import android.content.Context import android.view.LayoutInflater import android.view.View @@ -9,40 +10,36 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.Item import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.ItemCartBinding import com.teavaro.ecommDemoApp.ui.ItemDescriptionDialogFragment -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import kotlinx.android.synthetic.main.item_cart.view.* -import kotlinx.android.synthetic.main.item_cart.view.txtPrice -import kotlinx.android.synthetic.main.item_cart.view.txtTitle -import kotlinx.android.synthetic.main.item_shop.view.* -class CartAdapter(context: Context, - private val listItems: List) : - ArrayAdapter(context, 0, listItems) { +class CartAdapter(context: Context, private val listItems: List) : + ArrayAdapter(context, 0, listItems) { + @SuppressLint("SetTextI18n") override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val layout = LayoutInflater.from(context).inflate(R.layout.item_cart,parent, false) - + val binding = if (convertView != null) + ItemCartBinding.bind(convertView) + else + ItemCartBinding.inflate(LayoutInflater.from(context), parent, false) val item = listItems[position] - val subTotal: Float = item.price * item.countOnCart - layout.txtTitle.text = item.title - layout.txtPrice.text = item.price.toString() - layout.txtCount.text = item.countOnCart.toString() - layout.txtSubTotal.text = "$$subTotal / piece" - - layout.btnRemove.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "removeFromCart") - Store.removeItemFromCart(item.id) + val subTotal: Float = item.price * item.countInCart + binding.txtTitle.text = item.title + binding.txtPrice.text = item.price.toString() + binding.txtCount.text = item.countInCart.toString() + binding.txtSubTotal.text = "$$subTotal / piece" + binding.btnRemove.setOnClickListener { + TrackUtils.click("remove_item_from_cart" + "," + item.data) + Store.removeItemFromCart(item.itemId) parent.findNavController().navigate(R.id.navigation_cart) Toast.makeText(context, "Product removed!", Toast.LENGTH_SHORT).show() } - - layout.txtTitle.setOnClickListener{ + binding.txtTitle.setOnClickListener{ ItemDescriptionDialogFragment.open((context as AppCompatActivity).supportFragmentManager, item) } - - return layout + return binding.root } } \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartFragment.kt index 1d9e088..49d88dd 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/cart/CartFragment.kt @@ -12,8 +12,9 @@ import androidx.lifecycle.ViewModelProvider import androidx.navigation.findNavController import com.teavaro.ecommDemoApp.R import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.StringUtils +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentCartBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK class CartFragment : Fragment() { @@ -31,12 +32,12 @@ class CartFragment : Fragment() { val cartViewModel = ViewModelProvider(this).get(CartViewModel::class.java) - FunnelConnectSDK.cdp().logEvent("Navigation", "cart") + TrackUtils.impression("cart_view") _binding = FragmentCartBinding.inflate(inflater, container, false) val root: View = binding.root - var list = Store.getItemsCart() + val list = Store.getItemsCart() val cartAdapter = CartAdapter(requireContext(), list) for (pos in 0..list.lastIndex){ container?.let { @@ -52,22 +53,41 @@ class CartFragment : Fragment() { binding.layTotal.visibility = LinearLayout.VISIBLE binding.btnCheckout.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "dialogCheckout") + TrackUtils.impression("dialog_checkout") val builder = AlertDialog.Builder(context) builder.setTitle("Checkout confirmation") .setMessage("Do you want to proceed with checkout?") .setNegativeButton("Cancel") {_,_ -> - FunnelConnectSDK.cdp().logEvent("Button", "cancelCheckout") + TrackUtils.click("cancel_checkout") } .setPositiveButton("Proceed") { _, _ -> - FunnelConnectSDK.cdp().logEvent("Button", "proceedCheckout") + TrackUtils.click("proceed_checkout") Store.removeAllCartItems() - root.findNavController().navigate(R.id.navigation_home) + root.findNavController().navigate(R.id.navigation_cart) Toast.makeText(context, "Success!", Toast.LENGTH_SHORT).show() } .create().show() } + binding.btnClearCart.setOnClickListener { + TrackUtils.click("clear_cart") + val builder = AlertDialog.Builder(context) + builder.setTitle("Clear confirmation") + .setMessage("Do you want to clear the cart?") + .setNegativeButton("Cancel") {_,_ -> + TrackUtils.click("clear_cart_cancel") + } + .setPositiveButton("Proceed") { _, _ -> + val acId = Store.addAbandonedCart(Store.getItemsCart()) + StringUtils.setClipboard(requireContext(), "http://www.teavarodemoapp.com?ab_cart_id=$acId") + TrackUtils.click("clear_cart_confirm") + Store.removeAllCartItems() + root.findNavController().navigate(R.id.navigation_cart) + Toast.makeText(context, "Cart cleared!", Toast.LENGTH_SHORT).show() + } + .create().show() + } + return root } diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/emails/EmailsFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/emails/EmailsFragment.kt new file mode 100644 index 0000000..50fddc3 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/emails/EmailsFragment.kt @@ -0,0 +1,65 @@ +package com.teavaro.ecommDemoApp.ui.emails + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.FragmentEmailsBinding +import com.teavaro.ecommDemoApp.ui.notifications.NotificationsViewModel + + +class EmailsFragment : Fragment() { + + private var _binding: FragmentEmailsBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val loginViewModel = + ViewModelProvider(this).get(NotificationsViewModel::class.java) + + TrackUtils.impression("emails_view") + + _binding = FragmentEmailsBinding.inflate(inflater, container, false) + val root: View = binding.root + + binding.identClick.setOnClickListener { + Store.userId?.let { + Store.getClickIdentLink(requireContext())?.let { + shareLink("Ident click link from AndroidDemoApp", it) + } + } + } + + binding.abandonedCart.setOnClickListener { + val acId = Store.getAbCartId() + val abandonedCartLink = "http://www.teavarodemoapp.com?ab_cart_id=$acId" + shareLink("Abandoned cart link from AndroidDemoApp", abandonedCartLink) + } + return root + } + + fun shareLink(subject: String, body: String) { + val intent = Intent(Intent.ACTION_SEND) + intent.putExtra(Intent.EXTRA_SUBJECT, subject) + intent.putExtra(Intent.EXTRA_TEXT, body) + intent.type = "text/plain" + startActivity(Intent.createChooser(intent, "Send Email using:")) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/home/HomeFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/home/HomeFragment.kt index ca8028e..940ba74 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/home/HomeFragment.kt @@ -1,28 +1,27 @@ package com.teavaro.ecommDemoApp.ui.home +import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.webkit.WebResourceRequest -import android.webkit.WebResourceResponse +import android.webkit.JavascriptInterface import android.webkit.WebView import android.webkit.WebViewClient import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager import androidx.lifecycle.ViewModelProvider -import androidx.navigation.findNavController import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.MraidController import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentHomeBinding import com.teavaro.ecommDemoApp.ui.shop.ShopAdapter -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK + class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null - // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! @@ -35,38 +34,97 @@ class HomeFragment : Fragment() { val homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java) - FunnelConnectSDK.cdp().logEvent("Navigation", "home") - _binding = FragmentHomeBinding.inflate(inflater, container, false) val root: View = binding.root - var list = Store.getItemsOffer() - val shopAdapter = ShopAdapter(requireContext(), list) - for (pos in 0..list.lastIndex){ - binding.listItems.addView(shopAdapter.getView(pos, view, container!!)) - } + TrackUtils.impression("home_view") + Store.section = "home" + + refreshOfferItems(container!!) binding.btnExplore.setOnClickListener { - root.findNavController().navigate(R.id.navigation_shop) + TrackUtils.click("explore") + Store.navigateAction?.invoke(R.id.navigation_shop) + } + + Store.refreshCeltraAd = { + if (Store.section == "home") + loadAd() } - loadAd() return root } + private fun refreshOfferItems(container: ViewGroup) { + var list = Store.listOffers + val shopAdapter = ShopAdapter(requireContext(), list) + shopAdapter.notifyDataSetChanged() + for (pos in 0..list.lastIndex) { + binding.listItems.addView(shopAdapter.getView(pos, view, container)) + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null } + /** Instantiate the interface and set the context */ + class WebAppInterface( + private var context: Context, + private var supportFragmentManager: FragmentManager + ) { + /** Show a toast from the web page */ + @JavascriptInterface + fun postMessage(data: String) { + Store.processCelraAction(context, data, supportFragmentManager) + } + } + private fun loadAd() { +// if(Store.webView == null) { + binding.webView.removeAllViews() + var webView = WebView(requireContext()) val html = Store.getBanner() - binding.webView.settings.javaScriptEnabled = true - binding.webView.loadDataWithBaseURL( + webView.webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView, url: String) { + Store.webView = webView + } + } + webView.settings.javaScriptEnabled = true + webView.settings.loadWithOverviewMode = true + webView.settings.useWideViewPort = true + webView.addJavascriptInterface( + WebAppInterface( + requireContext(), + parentFragmentManager + ), "Android" + ) + webView.loadDataWithBaseURL( "http://www.example.com/", html, "text/html", "UTF-8", null ) + binding.webView.addView(webView) +// } +// else{ +// Store.webView?.let { +// binding.webView.addView(it) +// } +// } } -} \ No newline at end of file + + override fun onPause() { + super.onPause() + binding.webView.removeAllViews() + } + + override fun onResume() { + super.onResume() + if (Store.infoResponse != null) + loadAd() + } +} + + diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/ids/IdsFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/ids/IdsFragment.kt new file mode 100644 index 0000000..f2ac5d9 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/ids/IdsFragment.kt @@ -0,0 +1,65 @@ +package com.teavaro.ecommDemoApp.ui.ids + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.FragmentIdsBinding +import com.teavaro.ecommDemoApp.ui.notifications.NotificationsViewModel + + +class IdsFragment : Fragment() { + + private var _binding: FragmentIdsBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val loginViewModel = + ViewModelProvider(this).get(NotificationsViewModel::class.java) + + TrackUtils.impression("ids_view") + + _binding = FragmentIdsBinding.inflate(inflater, container, false) + val root: View = binding.root + + refreshIds() + + binding.btnRefresh.setOnClickListener { + refreshIds() + } + return root + } + + fun refreshIds(){ + binding.txtUserid.text = Store.userId + binding.txtUmid.text = Store.umid + binding.txtAtid.text = Store.atid + binding.txtMtid.text = Store.mtid + binding.txtInfo.text = Store.attributes + } + + fun shareLink(subject: String, body: String) { + val intent = Intent(Intent.ACTION_SEND) + intent.putExtra(Intent.EXTRA_SUBJECT, subject) + intent.putExtra(Intent.EXTRA_TEXT, body) + intent.type = "text/plain" + startActivity(Intent.createChooser(intent, "Send Email using:")) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/login/LoginFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/login/LoginFragment.kt index 94251af..c18e7e1 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/login/LoginFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/login/LoginFragment.kt @@ -1,5 +1,6 @@ package com.teavaro.ecommDemoApp.ui.login +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -8,16 +9,22 @@ import android.widget.Toast import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.navigation.findNavController -import com.swrve.sdk.SwrveIdentityResponse import com.swrve.sdk.SwrveSDK import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.LogInMenu import com.teavaro.ecommDemoApp.core.Store -import com.teavaro.ecommDemoApp.core.StringUtils.stringToSha256String +import com.teavaro.ecommDemoApp.core.utils.SharedPreferenceUtils +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentLoginBinding -import com.teavaro.ecommDemoApp.ui.MainActivity -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import com.teavaro.funnelConnect.data.models.dataClasses.FCUser +import com.teavaro.ecommDemoApp.ui.notifications.NotificationsViewModel +import com.teavaro.funnelConnect.data.models.FCUser +import com.teavaro.funnelConnect.main.FunnelConnectSDK +import java.nio.charset.StandardCharsets +import java.util.Base64 +import javax.crypto.BadPaddingException +import javax.crypto.Cipher +import javax.crypto.IllegalBlockSizeException +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.SecretKeySpec class LoginFragment : Fragment() { @@ -34,24 +41,39 @@ class LoginFragment : Fragment() { savedInstanceState: Bundle? ): View { val loginViewModel = - ViewModelProvider(this).get(LoginViewModel::class.java) + ViewModelProvider(this).get(NotificationsViewModel::class.java) - FunnelConnectSDK.cdp().logEvent("Navigation", "login") + TrackUtils.impression("login_view") _binding = FragmentLoginBinding.inflate(inflater, container, false) val root: View = binding.root binding.btnLogin.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "login") + TrackUtils.click("login") if (!binding.edtEmail.text.isNullOrEmpty() && !binding.edtPassword.text.isNullOrEmpty()) { - val emailCoded = stringToSha256String(binding.edtEmail.text.toString()) - FunnelConnectSDK.cdp().setUser(FCUser("slsc", emailCoded),{ - Store.infoResponse = it - }) - Store.isLogin = true - root.findNavController().navigate(R.id.navigation_settings) - SwrveSDK.start(parentFragment?.activity, FunnelConnectSDK.cdp().getUmid()) - Toast.makeText(context, "Login success!" + FunnelConnectSDK.cdp().getUmid(), Toast.LENGTH_SHORT).show() + if (FunnelConnectSDK.isInitialized() && Store.isNbaPermissionAccepted()) { + binding.btnLogin.text = "Processing..." + binding.btnLogin.isEnabled = false + binding.edtEmail.text.toString().encryptCBC()?.let {userId -> + FunnelConnectSDK.setUser(FCUser("enemail", userId), { + Store.infoResponse = it + Store.updateFCData(it) + Store.umid = FunnelConnectSDK.getUMID() + Store.userId = userId + SharedPreferenceUtils.setUserId(requireContext(), userId) + SharedPreferenceUtils.setLogin(requireContext(), true) + root.findNavController().navigate(R.id.navigation_settings) + SwrveSDK.start(parentFragment?.activity, Store.umid) + Toast.makeText(context, "Login success!", Toast.LENGTH_SHORT).show() + },{ + binding.btnLogin.text = "LOG IN" + binding.btnLogin.isEnabled = true + }) + } + } + else{ + Store.showPermissionsDialog(requireActivity(), parentFragmentManager) + } } else Toast.makeText(context, "Need to insert email and password!", Toast.LENGTH_SHORT) .show() @@ -63,4 +85,61 @@ class LoginFragment : Fragment() { super.onDestroyView() _binding = null } + + private fun String.encryptCBC(): String? { + val keyBytes = byteArrayOf( + 46, + -101, + 23, + 102, + -56, + -64, + -112, + 11, + 98, + 39, + -111, + 33, + -102, + 19, + -83, + -92, + 24, + 89, + -16, + 90, + 7, + 12, + -108, + -109, + -123, + -11, + -19, + -50, + -79, + 56, + 5, + -126 + ) + val key = SecretKeySpec(keyBytes, "AES") + val ivBytes = ByteArray(16) // 16 bytes filled with zeroes + + val iv = IvParameterSpec(ivBytes) + + val encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + encryptCipher.init(Cipher.ENCRYPT_MODE, key, iv) + + return encrypt(encryptCipher, this) + } + + @Throws(IllegalBlockSizeException::class, BadPaddingException::class) + fun encrypt(encryptCipher: Cipher, plaintext: String): String? { + val cipherTextBytes: ByteArray = + encryptCipher.doFinal(plaintext.toByteArray(StandardCharsets.UTF_8)) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Base64.getUrlEncoder().encodeToString(cipherTextBytes) + } else { + TODO("VERSION.SDK_INT < O") + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsFragment.kt new file mode 100644 index 0000000..da7f4cc --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsFragment.kt @@ -0,0 +1,75 @@ +package com.teavaro.ecommDemoApp.ui.notifications + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider +import com.teavaro.ecommDemoApp.core.utils.PushNotification +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.FragmentNotificationsBinding +import com.teavaro.funnelConnect.main.FunnelConnectSDK + + +class NotificationsFragment : Fragment() { + + private var _binding: FragmentNotificationsBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val loginViewModel = + ViewModelProvider(this).get(NotificationsViewModel::class.java) + + TrackUtils.impression("notifications_view") + + _binding = FragmentNotificationsBinding.inflate(inflater, container, false) + val root: View = binding.root + + binding.cashews.setOnClickListener { + FunnelConnectSDK.getUMID()?.let { + PushNotification.sendCashews(it){ + Toast.makeText(requireContext(), "Notification sent!", Toast.LENGTH_LONG).show() + } + } + } + + binding.shop.setOnClickListener { + FunnelConnectSDK.getUMID()?.let { + PushNotification.sendShop(it){ + Toast.makeText(requireContext(), "Notification sent!", Toast.LENGTH_LONG).show() + } + } + } + + binding.abandonedCart.setOnClickListener { + FunnelConnectSDK.getUMID()?.let { + PushNotification.sendAbandonedCart(it){ + Toast.makeText(requireContext(), "Notification sent!", Toast.LENGTH_LONG).show() + } + } + } + + binding.identClick.setOnClickListener { + FunnelConnectSDK.getUMID()?.let { + PushNotification.sendIdentClick(it){ + Toast.makeText(requireContext(), "Notification sent!", Toast.LENGTH_LONG).show() + } + } + } + return root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsViewModel.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsViewModel.kt new file mode 100644 index 0000000..903882d --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/notifications/NotificationsViewModel.kt @@ -0,0 +1,13 @@ +package com.teavaro.ecommDemoApp.ui.notifications + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class NotificationsViewModel : ViewModel() { + + private val _text = MutableLiveData().apply { + value = "This is login Fragment" + } + val text: LiveData = _text +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/PermissionConsentDialogFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/PermissionConsentDialogFragment.kt similarity index 82% rename from app/src/main/java/com/teavaro/ecommDemoApp/ui/PermissionConsentDialogFragment.kt rename to app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/PermissionConsentDialogFragment.kt index 5a2ca6f..231c54a 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/PermissionConsentDialogFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/PermissionConsentDialogFragment.kt @@ -1,4 +1,4 @@ -package com.teavaro.ecommDemoApp.ui +package com.teavaro.ecommDemoApp.ui.permissions import android.app.Dialog import android.os.Bundle @@ -7,10 +7,11 @@ import android.view.Window import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.SharedPreferenceUtils +import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentFPermissionsConsentBinding import com.teavaro.ecommDemoApp.viewBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK +import com.teavaro.funnelConnect.main.FunnelConnectSDK class PermissionConsentDialogFragment : DialogFragment(R.layout.fragment_f_permissions_consent) { @@ -22,7 +23,7 @@ class PermissionConsentDialogFragment : DialogFragment(R.layout.fragment_f_permi // override fun getTheme() = R.style.FullScreenDimmedDialogFragment override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - FunnelConnectSDK.cdp().logEvent("Navigation", "permissionDialog") + TrackUtils.impression("permission_view") val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) dialog.setCancelable(true) @@ -54,10 +55,10 @@ class PermissionConsentDialogFragment : DialogFragment(R.layout.fragment_f_permi } private fun initialPresets() { - FunnelConnectSDK.cdp().getPermissions().let { - binding.swCookies.isChecked = it.getPermission("CS-TMI") - binding.swNetwork.isChecked = it.getPermission("CS-OPT") - binding.swPersonal.isChecked = it.getPermission("CS-NBA") + FunnelConnectSDK.getPermissions().let { + binding.swCookies.isChecked = it.getPermission(Store.keyOm) + binding.swNetwork.isChecked = it.getPermission(Store.keyOpt) + binding.swPersonal.isChecked = it.getPermission(Store.keyNba) } } diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/UtiqConsent.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/UtiqConsent.kt new file mode 100644 index 0000000..6d5d786 --- /dev/null +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/permissions/UtiqConsent.kt @@ -0,0 +1,61 @@ +package com.teavaro.ecommDemoApp.ui.permissions + +/** + * A simple [Fragment] subclass. + * Use the [UtiqConsent.newInstance] factory method to + * create an instance of this fragment. + */ + +import android.app.Dialog +import android.os.Bundle +import android.view.View +import android.view.Window +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager +import com.teavaro.ecommDemoApp.R +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.FragmentUtiqConsentBinding +import com.teavaro.ecommDemoApp.viewBinding + +class UtiqConsent : DialogFragment(R.layout.fragment_utiq_consent) { + + private val binding by viewBinding(FragmentUtiqConsentBinding::bind) + private var action: ((consent: Boolean) -> Unit)? = + null + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + TrackUtils.impression("permission_view") + val dialog = super.onCreateDialog(savedInstanceState) + dialog.window?.requestFeature(Window.FEATURE_NO_TITLE) + dialog.setCancelable(true) + dialog.setCanceledOnTouchOutside(true) + return dialog + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.acceptButton.setOnClickListener { + this.action?.invoke(true) + this.dismiss() + } + binding.cancelButton.setOnClickListener { + this.action?.invoke(false) + this.dismiss() + } + binding.btnClose.setOnClickListener { + this.dismiss() + } + } + + companion object { + fun open( + fm: FragmentManager, + action: (omPermissionAccepted: Boolean) -> Unit = { _ -> } + ) { + val dialogFragment = UtiqConsent() + dialogFragment.action = action + dialogFragment.show(fm, null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/settings/SettingsFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/settings/SettingsFragment.kt index cd25047..724c120 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/settings/SettingsFragment.kt @@ -2,21 +2,18 @@ package com.teavaro.ecommDemoApp.ui.settings import android.app.AlertDialog import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.Toast -import androidx.fragment.app.findFragment +import androidx.fragment.app.Fragment import androidx.navigation.findNavController import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.HTTPAsyncTask -import com.teavaro.ecommDemoApp.core.LogInMenu -import com.teavaro.ecommDemoApp.core.SharedPreferenceUtils import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.SharedPreferenceUtils +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentSettingsBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK class SettingsFragment : Fragment() { @@ -31,9 +28,10 @@ class SettingsFragment : Fragment() { _binding = FragmentSettingsBinding.inflate(inflater, container, false) val root: View = binding.root - FunnelConnectSDK.cdp().logEvent("Navigation", "settings") + TrackUtils.impression("settings_view") + Store.section = "settings" - if(Store.isLogin){ + if(SharedPreferenceUtils.isLogin(requireContext())){ binding.logOut.visibility = Button.VISIBLE binding.logIn.visibility = Button.GONE } @@ -44,16 +42,20 @@ class SettingsFragment : Fragment() { binding.clearData.setOnClickListener{ clearData() + root.findNavController().navigate(R.id.navigation_settings) Toast.makeText(requireContext(), "Data cleared!", Toast.LENGTH_LONG).show() } - binding.sendNotification.setOnClickListener { - FunnelConnectSDK.cdp().getUmid()?.let { - val httpAsyncTask = HTTPAsyncTask{ - Toast.makeText(requireContext(), "Notification sent!", Toast.LENGTH_LONG).show() - } - httpAsyncTask.execute(it, "Swrve App Push Notification...") - } + binding.notifications.setOnClickListener { + root.findNavController().navigate(R.id.navigation_notifications) + } + + binding.ids.setOnClickListener { + root.findNavController().navigate(R.id.navigation_ids) + } + + binding.email.setOnClickListener { + root.findNavController().navigate(R.id.navigation_email) } binding.logIn.setOnClickListener { @@ -61,16 +63,18 @@ class SettingsFragment : Fragment() { } binding.logOut.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "dialogLogout") + TrackUtils.click("dialog_logout") val builder = AlertDialog.Builder(requireContext()) builder.setTitle("Logout confirmation") .setMessage("Do you want to proceed with the logout?") .setNegativeButton("Cancel") {_,_ -> - FunnelConnectSDK.cdp().logEvent("Button", "cancelLogout") + TrackUtils.click("cancel_logout") } .setPositiveButton("Proceed") { _, _ -> - FunnelConnectSDK.cdp().logEvent("Button", "proceedLogout") - Store.isLogin = false + TrackUtils.click("proceed_logout") + SharedPreferenceUtils.setLogin(requireContext(), false) + SharedPreferenceUtils.setUserId(requireContext(), "") + Store.userId = "" root.findNavController().navigate(R.id.navigation_settings) Toast.makeText(requireContext(), "Logout success!", Toast.LENGTH_SHORT).show() } @@ -78,16 +82,16 @@ class SettingsFragment : Fragment() { } binding.consentManagement.setOnClickListener { - Store.showPermissionsDialog(requireContext(), parentFragmentManager) + Store.showPermissionsDialog(requireActivity(), parentFragmentManager) } - binding.stubMode.isChecked = SharedPreferenceUtils.isStubMode(requireContext()) + binding.stubMode.isChecked = SharedPreferenceUtils.getStubToken(requireContext()) != null binding.stubMode.setOnCheckedChangeListener { _, isStub -> - clearData() - SharedPreferenceUtils.setStubMode(requireContext(), isStub) - Store.showPermissionsDialog(requireContext() ,parentFragmentManager) + if(isStub) { + SharedPreferenceUtils.setStubToken(requireContext(), Store.stubToken) + Store.showUtiqConsent(requireActivity(), parentFragmentManager) + } } - return root } @@ -97,7 +101,6 @@ class SettingsFragment : Fragment() { } private fun clearData(){ - FunnelConnectSDK.clearData() - FunnelConnectSDK.clearCookies() + Store.clearData(requireContext()) } } \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopAdapter.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopAdapter.kt index b32dabf..c49cd73 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopAdapter.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopAdapter.kt @@ -7,82 +7,75 @@ import android.view.ViewGroup import android.widget.* import androidx.appcompat.app.AppCompatActivity import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.Item import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.ItemShopBinding import com.teavaro.ecommDemoApp.ui.ItemDescriptionDialogFragment -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import kotlinx.android.synthetic.main.item_shop.view.* - class ShopAdapter(context: Context, - private val listItems: List) : - ArrayAdapter(context, 0, listItems) { - - private lateinit var layout: View + private val listItems: List) : + ArrayAdapter(context, 0, listItems) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - layout = LayoutInflater.from(context).inflate(R.layout.item_shop,parent, false) - + val binding = if (convertView != null) + ItemShopBinding.bind(convertView) + else + ItemShopBinding.inflate(LayoutInflater.from(context), parent, false) val item = listItems[position] - layout.txtTitle.text = item.title - layout.txtPrice.text = "$${item.price}" + binding.txtTitle.text = item.title + binding.txtPrice.text = "$${item.price}" val imgId: Int = parent.resources.getIdentifier(item.picture, "drawable", "com.teavaro.ecommDemoApp") - layout.imgPicture.setImageResource(imgId) - + binding.imgPicture.setImageResource(imgId) if(!item.isInStock) { - layout.btnAddToCart.visibility = Button.GONE - layout.outOfStock.visibility = TextView.VISIBLE + binding.btnAddToCart.visibility = Button.GONE + binding.outOfStock.visibility = TextView.VISIBLE } - - - layout.btnAddToCart.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "addToCart") - Store.addItemToCart(item.id) + binding.btnAddToCart.setOnClickListener { + TrackUtils.click("add_to_cart" + "," + item.data) + Store.addItemToCart(item.itemId) Toast.makeText(context, "Product added!", Toast.LENGTH_SHORT).show() } - - layout.btnAddToWish.let { imageView -> + binding.btnAddToWish.let { imageView -> setWishPicture(imageView, item) imageView.setOnClickListener { - if(!item.isWish) { - FunnelConnectSDK.cdp().logEvent("Button", "addToWish") - Store.addItemToWish(item.id) - item.isWish = true + if(!item.isInWish) { + TrackUtils.click("add_to_wishlist" + "," + item.data) + Store.addItemToWish(item.itemId) + item.isInWish = true Toast.makeText(context, "Product added!", Toast.LENGTH_SHORT).show() } else { - FunnelConnectSDK.cdp().logEvent("Button", "removeFromWish") - Store.removeItemFromWish(item.id) - item.isWish = false + TrackUtils.click("remove_from_wishlist" + "," + item.data) + Store.removeItemFromWish(item.itemId) + item.isInWish = false Toast.makeText(context, "Product removed!", Toast.LENGTH_SHORT).show() } - setWishPicture(imageView as ImageView, item) + setWishPicture(imageView, item) } } - - layout.imgPicture.setOnClickListener{ - if(item.isWish) { + binding.imgPicture.setOnClickListener{ + if(item.isInWish) { ItemDescriptionDialogFragment.open( (context as AppCompatActivity).supportFragmentManager, item, { - Store.addItemToCart(item.id) + Store.addItemToCart(item.itemId) }) } else{ ItemDescriptionDialogFragment.open((context as AppCompatActivity).supportFragmentManager, item, { - Store.addItemToCart(item.id) + Store.addItemToCart(item.itemId) },{ - Store.addItemToWish(item.id) + Store.addItemToWish(item.itemId) }) } } - - return layout + return binding.root } - private fun setWishPicture(imageView: ImageView, item: Item){ - if(item.isWish) + private fun setWishPicture(imageView: ImageView, item: ItemEntity) { + if(item.isInWish) imageView.setImageResource(R.drawable.ic_wishlist_red_24dp) else imageView.setImageResource(R.drawable.ic_wishlist_black_24dp) diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopFragment.kt index cdba3ef..cb43bad 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/shop/ShopFragment.kt @@ -1,14 +1,20 @@ package com.teavaro.ecommDemoApp.ui.shop +import android.content.Context +import android.content.Intent +import android.net.Uri import android.os.Bundle +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.SharedPreferenceUtils +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentShopBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK class ShopFragment : Fragment() { @@ -21,9 +27,10 @@ class ShopFragment : Fragment() { savedInstanceState: Bundle? ): View { val shopViewModel = - ViewModelProvider(this).get(ShopViewModel::class.java) + ViewModelProvider(this)[ShopViewModel::class.java] - FunnelConnectSDK.cdp().logEvent("Navigation", "shop") + TrackUtils.impression("shop_view") + Store.section = "shop" _binding = FragmentShopBinding.inflate(inflater, container, false) val root: View = binding.root @@ -33,10 +40,35 @@ class ShopFragment : Fragment() { for (pos in 0..list.lastIndex){ binding.listItems.addView(shopAdapter.getView(pos, view, container!!)) } + if(SharedPreferenceUtils.isLogin(requireContext())) { + val btnSeeMore = Button(context).apply { + text = "See More Products" + layoutParams = ViewGroup.MarginLayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { + marginStart = 16.dpToPx(context) + marginEnd = 16.dpToPx(context) + } + isAllCaps = true + gravity = Gravity.CENTER + setOnClickListener { + val url = Store.getClickIdentLink(context) + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + context.startActivity(intent) + } + } + binding.listItems.addView(btnSeeMore) + } return root } + // Extension function to convert dp to px + fun Int.dpToPx(context: Context): Int { + return (this * context.resources.displayMetrics.density).toInt() + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishAdapter.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishAdapter.kt index a34a7a3..4f57b28 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishAdapter.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishAdapter.kt @@ -11,54 +11,47 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController import com.teavaro.ecommDemoApp.R -import com.teavaro.ecommDemoApp.core.Item import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.room.ItemEntity +import com.teavaro.ecommDemoApp.core.utils.TrackUtils +import com.teavaro.ecommDemoApp.databinding.ItemWishBinding import com.teavaro.ecommDemoApp.ui.ItemDescriptionDialogFragment -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK -import kotlinx.android.synthetic.main.item_cart.view.* -import kotlinx.android.synthetic.main.item_shop.view.btnAddToCart -import kotlinx.android.synthetic.main.item_wish.view.* -import kotlinx.android.synthetic.main.item_wish.view.btnRemove -import kotlinx.android.synthetic.main.item_wish.view.txtPrice -import kotlinx.android.synthetic.main.item_wish.view.txtTitle class WishAdapter(context: Context, - private val listItems: List) : - ArrayAdapter(context, 0, listItems) { + private val listItems: List) : + ArrayAdapter(context, 0, listItems) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val layout = LayoutInflater.from(context).inflate(R.layout.item_wish,parent, false) - + val binding = if (convertView != null) + ItemWishBinding.bind(convertView) + else + ItemWishBinding.inflate(LayoutInflater.from(context), parent, false) val item = listItems[position] - layout.txtTitle.text = item.title - layout.txtPrice.text = "$${item.price}" - + binding.txtTitle.text = item.title + binding.txtPrice.text = "$${item.price}" if(item.isInStock) - layout.inStock.visibility = ImageView.VISIBLE + binding.inStock.visibility = ImageView.VISIBLE else { - layout.noStock.visibility = ImageView.VISIBLE - layout.btnAddToCart.visibility = Button.GONE + binding.noStock.visibility = ImageView.VISIBLE + binding.btnAddToCart.visibility = Button.GONE } - - layout.btnRemove.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "removeFromWish") - Store.removeItemFromWish(item.id) + binding.btnRemove.setOnClickListener { + TrackUtils.click( "remove_from_wishlist" + "," + item.data) + Store.removeItemFromWish(item.itemId) parent.findNavController().navigate(R.id.navigation_wishlist) Toast.makeText(context, "Product removed!", Toast.LENGTH_SHORT).show() } - - layout.btnAddToCart.setOnClickListener { - FunnelConnectSDK.cdp().logEvent("Button", "addToCart") - Store.addItemToCart(item.id) + binding.btnAddToCart.setOnClickListener { + TrackUtils.click( "add_to_cart" + "," + item.data) + Store.addItemToCart(item.itemId) Toast.makeText(context, "Product added!", Toast.LENGTH_SHORT).show() } - - layout.txtTitle.setOnClickListener{ + binding.txtTitle.setOnClickListener{ ItemDescriptionDialogFragment.open((context as AppCompatActivity).supportFragmentManager, item, { - Store.addItemToCart(item.id) + TrackUtils.click( "add_to_cart" + "," + item.data) + Store.addItemToCart(item.itemId) }) } - - return layout + return binding.root } } \ No newline at end of file diff --git a/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishlistFragment.kt b/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishlistFragment.kt index 41afa37..1f9a5ad 100644 --- a/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishlistFragment.kt +++ b/app/src/main/java/com/teavaro/ecommDemoApp/ui/wishlist/WishlistFragment.kt @@ -8,8 +8,8 @@ import android.widget.LinearLayout import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import com.teavaro.ecommDemoApp.core.Store +import com.teavaro.ecommDemoApp.core.utils.TrackUtils import com.teavaro.ecommDemoApp.databinding.FragmentWishlistBinding -import com.teavaro.funnelConnect.core.initializer.FunnelConnectSDK class WishlistFragment : Fragment() { @@ -27,7 +27,8 @@ class WishlistFragment : Fragment() { val wishlistViewModel = ViewModelProvider(this).get(WishlistViewModel::class.java) - FunnelConnectSDK.cdp().logEvent("Navigation", "wishlist") + TrackUtils.impression("wishlist_view") + Store.section = "wishlist" _binding = FragmentWishlistBinding.inflate(inflater, container, false) val root: View = binding.root diff --git a/app/src/main/res/drawable/app_icon_background.xml b/app/src/main/res/drawable/app_icon_background.xml new file mode 100644 index 0000000..36707c2 --- /dev/null +++ b/app/src/main/res/drawable/app_icon_background.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/bg_special_offer.png b/app/src/main/res/drawable/bg_special_offer.png deleted file mode 100644 index 2d95ad5..0000000 Binary files a/app/src/main/res/drawable/bg_special_offer.png and /dev/null differ diff --git a/app/src/main/res/drawable/burst.jpg b/app/src/main/res/drawable/burst.jpg deleted file mode 100644 index 8f70074..0000000 Binary files a/app/src/main/res/drawable/burst.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/cashews.jpg b/app/src/main/res/drawable/cashews.jpg new file mode 100644 index 0000000..19fcbd0 Binary files /dev/null and b/app/src/main/res/drawable/cashews.jpg differ diff --git a/app/src/main/res/drawable/cauliflower.jpg b/app/src/main/res/drawable/cauliflower.jpg deleted file mode 100644 index 3f0848a..0000000 Binary files a/app/src/main/res/drawable/cauliflower.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/coleslaw.jpeg b/app/src/main/res/drawable/coleslaw.jpeg new file mode 100644 index 0000000..3ced2ca Binary files /dev/null and b/app/src/main/res/drawable/coleslaw.jpeg differ diff --git a/app/src/main/res/drawable/cookies.jpg b/app/src/main/res/drawable/cookies.jpg new file mode 100644 index 0000000..a2018f1 Binary files /dev/null and b/app/src/main/res/drawable/cookies.jpg differ diff --git a/app/src/main/res/drawable/crinklys.jpg b/app/src/main/res/drawable/crinklys.jpg deleted file mode 100644 index 559e1a4..0000000 Binary files a/app/src/main/res/drawable/crinklys.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/grapes.jpg b/app/src/main/res/drawable/grapes.jpg deleted file mode 100644 index bbc79b3..0000000 Binary files a/app/src/main/res/drawable/grapes.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/hillshire.jpg b/app/src/main/res/drawable/hillshire.jpg new file mode 100644 index 0000000..dcc0e7f Binary files /dev/null and b/app/src/main/res/drawable/hillshire.jpg differ diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png deleted file mode 100644 index 5f02c8a..0000000 Binary files a/app/src/main/res/drawable/logo.png and /dev/null differ diff --git a/app/src/main/res/drawable/mixed.jpg b/app/src/main/res/drawable/mixed.jpg deleted file mode 100644 index 60805bf..0000000 Binary files a/app/src/main/res/drawable/mixed.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/paprika.jpg b/app/src/main/res/drawable/paprika.jpg deleted file mode 100644 index e23480b..0000000 Binary files a/app/src/main/res/drawable/paprika.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/porridge.jpg b/app/src/main/res/drawable/porridge.jpg new file mode 100644 index 0000000..b696aab Binary files /dev/null and b/app/src/main/res/drawable/porridge.jpg differ diff --git a/app/src/main/res/drawable/prod_snapple.jpg b/app/src/main/res/drawable/prod_snapple.jpg deleted file mode 100644 index 391dc82..0000000 Binary files a/app/src/main/res/drawable/prod_snapple.jpg and /dev/null differ diff --git a/app/src/main/res/drawable/teriyaki.jpg b/app/src/main/res/drawable/teriyaki.jpg new file mode 100644 index 0000000..c15d31c Binary files /dev/null and b/app/src/main/res/drawable/teriyaki.jpg differ diff --git a/app/src/main/res/drawable/tsarine.jpeg b/app/src/main/res/drawable/tsarine.jpeg new file mode 100644 index 0000000..d031486 Binary files /dev/null and b/app/src/main/res/drawable/tsarine.jpeg differ diff --git a/app/src/main/res/drawable/watermelon.jpg b/app/src/main/res/drawable/watermelon.jpg deleted file mode 100644 index e5ce4d3..0000000 Binary files a/app/src/main/res/drawable/watermelon.jpg and /dev/null differ diff --git a/app/src/main/res/layout/fragment_abandoned_cart_dialog.xml b/app/src/main/res/layout/fragment_abandoned_cart_dialog.xml new file mode 100644 index 0000000..a4c19a1 --- /dev/null +++ b/app/src/main/res/layout/fragment_abandoned_cart_dialog.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + +