SubscriptionViewModel.kt 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. package com.vpn.fastestvpnservice.viewmodels
  2. import android.app.Activity
  3. import android.content.Context
  4. import android.util.Base64
  5. import android.util.Log
  6. import androidx.activity.ComponentActivity
  7. import androidx.compose.runtime.livedata.observeAsState
  8. import androidx.compose.runtime.mutableStateOf
  9. import androidx.lifecycle.LiveData
  10. import androidx.lifecycle.MutableLiveData
  11. import androidx.lifecycle.ViewModel
  12. import com.android.billingclient.api.AcknowledgePurchaseParams
  13. import com.android.billingclient.api.BillingClient
  14. import com.android.billingclient.api.BillingClientStateListener
  15. import com.android.billingclient.api.BillingFlowParams
  16. import com.android.billingclient.api.BillingResult
  17. import com.android.billingclient.api.Purchase
  18. import com.android.billingclient.api.PurchasesUpdatedListener
  19. import com.android.billingclient.api.SkuDetails
  20. import com.android.billingclient.api.SkuDetailsParams
  21. import com.google.gson.Gson
  22. import com.google.gson.reflect.TypeToken
  23. import com.vpn.fastestvpnservice.R
  24. import de.blinkt.openvpn.core.App
  25. import com.vpn.fastestvpnservice.beans.DataResponse
  26. import com.vpn.fastestvpnservice.beans.DataResponseServers
  27. import com.vpn.fastestvpnservice.beans.Features
  28. import com.vpn.fastestvpnservice.beans.ProductFeatures
  29. import com.vpn.fastestvpnservice.beans.ServerData
  30. import com.vpn.fastestvpnservice.beans.SubscriptionPackageList
  31. import com.vpn.fastestvpnservice.customItems.getSelectedPosition
  32. import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
  33. import com.vpn.fastestvpnservice.retrofit.RetrofitNetworkHandling
  34. import com.vpn.fastestvpnservice.retrofit.WebServiceFactory
  35. import com.vpn.fastestvpnservice.screens.accountScreensAll.SubscriptionScreen
  36. import org.json.JSONArray
  37. import org.json.JSONObject
  38. import retrofit2.Call
  39. class SubscriptionViewModel constructor(context: Context, activity: ComponentActivity): ViewModel(), PurchasesUpdatedListener {
  40. var mutableLiveDataProducts = MutableLiveData<DataResponse<ArrayList<ProductFeatures>>>()
  41. var liveDataProducts: LiveData<DataResponse<ArrayList<ProductFeatures>>> = mutableLiveDataProducts
  42. val mutableLiveDataSubscription = MutableLiveData<DataResponseServers<ArrayList<ServerData>>>()
  43. var mutableLiveDataSkuDetails = MutableLiveData<MutableList<SkuDetails>>()
  44. var liveDataSkuDetails: LiveData<MutableList<SkuDetails>> = mutableLiveDataSkuDetails
  45. var mutableLiveDataProductsErrorStatus = MutableLiveData<Boolean>()
  46. var preferenceHelper: BasePreferenceHelper
  47. private var context: Context
  48. private var activity: ComponentActivity
  49. var mutableLiveDataNumber = MutableLiveData<Int>(0)
  50. val tag = "SubscriptionViewModel"
  51. val prefHelper = BasePreferenceHelper(context)
  52. private var skuDetailsList: List<SkuDetails>? = null
  53. var featuresList = MutableLiveData<MutableList<ProductFeatures>>()
  54. var featuresListSorted = MutableLiveData<MutableList<ProductFeatures>>()
  55. var featuresListSortedItems = MutableLiveData<MutableList<Features>>()
  56. var selectPriceList = MutableLiveData<MutableList<SubscriptionPackageList>>()
  57. private val billingClient: BillingClient by lazy {
  58. BillingClient.newBuilder(context)
  59. .setListener(this)
  60. .enablePendingPurchases()
  61. .build()
  62. }
  63. companion object {
  64. var selectedPosition: Int = 0
  65. }
  66. init {
  67. this.context = context
  68. this.activity = activity
  69. preferenceHelper = BasePreferenceHelper(context)
  70. }
  71. fun setSelectedPosition(num: Int) {
  72. Log.d("test_plan", "[1] num = $num")
  73. mutableLiveDataNumber.postValue(num)
  74. Log.d("test_plan", "[2] num = $num")
  75. }
  76. fun setProductsData(products: DataResponse<ArrayList<ProductFeatures>>) {
  77. mutableLiveDataProducts.value = products
  78. }
  79. fun getProducts(onProductResult: () -> Unit){
  80. WebServiceFactory.getInstance().getProducts().enqueue(
  81. RetrofitNetworkHandling<Any>(object :
  82. RetrofitNetworkHandling.ResponseCallback<Any>{
  83. override fun onSuccess(call: Call<Any>?, response: Any?) {
  84. try {
  85. val gson = Gson()
  86. val jsonString = gson.toJson(response)
  87. val type = object : TypeToken<DataResponse<ArrayList<ProductFeatures>>>() {}.type
  88. val data = gson.fromJson<DataResponse<ArrayList<ProductFeatures>>>(jsonString, type)
  89. Log.d("test_api_response_p", "Products try = ${data.status} ${data.message} ${data.data?.size}")
  90. data?.data?.let {
  91. preferenceHelper.saveFeaturesData(it)
  92. featuresList.value = it
  93. }
  94. if (data.data?.size == 0){
  95. onProductResult()
  96. }
  97. mutableLiveDataProducts.value = data
  98. mutableLiveDataProductsErrorStatus.value = false
  99. startConnection(getSelectedPosition())
  100. } catch (ex: Exception) {
  101. Log.d("test_api_response", "Products catch:")
  102. mutableLiveDataProductsErrorStatus.value = true
  103. }
  104. }
  105. override fun onFail(call: Call<Any>?, response: Any?) {
  106. Log.d("test_api_response", "Products onFail: ")
  107. mutableLiveDataProductsErrorStatus.value = true
  108. }
  109. override fun onError(call: Call<Any>?, response: Any?) {
  110. Log.d("test_api_response", "Products onError: ")
  111. mutableLiveDataProductsErrorStatus.value = true
  112. }
  113. }
  114. )
  115. )
  116. }
  117. fun create_subscription(transaction_id: String, receipt_data: String, productId: String) {
  118. Log.d("test_api_response", "create_subscription params = $transaction_id $receipt_data $productId")
  119. WebServiceFactory.getInstance().createSubscription(transaction_id, receipt_data, productId).enqueue(
  120. RetrofitNetworkHandling<Any>(object :
  121. RetrofitNetworkHandling.ResponseCallback<Any> {
  122. override fun onSuccess(call: Call<Any>?, response: Any?) {
  123. try {
  124. Log.d("test_api_response", "create_subscription try = $response")
  125. val gson = Gson()
  126. val jsonString = gson.toJson(response)
  127. val type = object : TypeToken<DataResponseServers<ArrayList<ServerData>>>() {}.type
  128. val data = gson.fromJson<DataResponseServers<ArrayList<ServerData>>>(jsonString, type)
  129. Log.d("test_api_response", "create_subscription try = ${data.status} ${data.message}")
  130. data?.let {
  131. mutableLiveDataSubscription.value = it
  132. }
  133. } catch (ex: Exception) {
  134. Log.d("test_api_response", "create_subscription catch = $response")
  135. }
  136. }
  137. override fun onFail(call: Call<Any>?, response: Any?) {
  138. Log.d("test_api_response", "create_subscription onFail = $response")
  139. }
  140. override fun onError(call: Call<Any>?, response: Any?) {
  141. Log.d("test_api_response", "create_subscription onError = $response")
  142. }
  143. })
  144. )
  145. }
  146. fun startConnection(selectedPosition: Int) {
  147. SubscriptionViewModel.selectedPosition = selectedPosition
  148. Log.d(tag, "startConnection Billing")
  149. billingClient.startConnection(object : BillingClientStateListener {
  150. override fun onBillingSetupFinished(billingResult: BillingResult) {
  151. if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
  152. Log.d(tag, "onBillingSetupFinished")
  153. Log.d(tag, "BILLING | startConnection | RESULT OK")
  154. onLoadProductsClicked()
  155. } else {
  156. Log.d(tag, "BILLING | startConnection | RESULT: ${billingResult.responseCode}")
  157. }
  158. }
  159. override fun onBillingServiceDisconnected() {
  160. Log.d(tag, "BILLING | onBillingServiceDisconnected | DISCONNECTED")
  161. }
  162. })
  163. }
  164. private fun onLoadProductsClicked() {
  165. Log.d(tag, "onLoadProductsClicked Billing")
  166. // val skuList = listOf("com.fastestvpn.vpn.one.month", "com.fastestvpn.vpn.one.year")
  167. val skuList: ArrayList<String> = ArrayList<String>()
  168. val identifierProduct = prefHelper.getFeaturesData()
  169. identifierProduct.forEachIndexed { index, productFeatures ->
  170. productFeatures.identifier?.let { skuList.add(it) }
  171. }
  172. skuList.forEachIndexed { index, s ->
  173. Log.d("skulist identidiers", s)
  174. }
  175. val skuDetailsListsSubs: MutableList<SkuDetails> = ArrayList<SkuDetails>()
  176. val params = SkuDetailsParams.newBuilder()
  177. params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
  178. billingClient.querySkuDetailsAsync(params.build())
  179. { billingResult, skuDetailsList ->
  180. if (billingResult.responseCode == BillingClient.BillingResponseCode.OK
  181. && skuDetailsList != null) {
  182. for (skuDetails in skuDetailsList) {
  183. Log.d(tag, "[1st] ${skuDetails.title} Billing")
  184. skuDetailsListsSubs.add(skuDetails)
  185. }
  186. params.setType(BillingClient.SkuType.SUBS)
  187. billingClient.querySkuDetailsAsync(params.build())
  188. { billingResults, skuDetailsLists ->
  189. if (billingResults.responseCode == BillingClient.BillingResponseCode.OK
  190. && skuDetailsLists != null) {
  191. for (skuDetails in skuDetailsLists) {
  192. Log.d(tag, "[2nd] ${skuDetails.title} Billing")
  193. skuDetailsListsSubs.add(skuDetails)
  194. }
  195. mutableLiveDataSkuDetails.postValue(skuDetailsListsSubs)
  196. // subscriptionProduct(selectedPosition, skuDetailsListsSubs, activity)
  197. initProductList(skuDetailsListsSubs)
  198. }
  199. }
  200. }
  201. }
  202. }
  203. fun subscriptionProduct(
  204. selectedPosition: Int,
  205. skuDetailsListsSubs: MutableList<SkuDetails>,
  206. activity: ComponentActivity
  207. ) {
  208. Log.d(tag, "subscriptionProduct Billing $skuDetailsListsSubs")
  209. if (skuDetailsListsSubs != null && skuDetailsListsSubs.isNotEmpty())
  210. {
  211. Log.d(tag, "subscriptionProduct IN Billing")
  212. val billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(
  213. skuDetailsListsSubs.get(selectedPosition)).build()
  214. billingClient.launchBillingFlow(activity, billingFlowParams)
  215. }
  216. }
  217. private fun initProductList(skuDetailsList: List<SkuDetails>) {
  218. Log.d("test_subscription_list", "skuDetailsList size = ${skuDetailsList.size}")
  219. this.skuDetailsList = skuDetailsList
  220. if (this.skuDetailsList?.size!! > 0) {
  221. Log.d("test_subscription_list", "skuDetailsList[2] size = ${skuDetailsList.size}")
  222. var boolValue: Boolean
  223. var freePeriod: String
  224. var title: String
  225. var selectFeatureListSorted = ArrayList<ProductFeatures>()
  226. val featuresListSortedData = ArrayList<ProductFeatures>()
  227. val selectPriceListData = ArrayList<SubscriptionPackageList>()
  228. featuresList.value?.let {
  229. for ((index, value) in skuDetailsList.withIndex()) {
  230. for ((indexed, values) in it.withIndex()) {
  231. if (value.sku == values.identifier) {
  232. Log.d("test_subscription_list", "Equal => $index + $indexed")
  233. featuresListSortedData.add(it.get(indexed))
  234. Log.d(
  235. "test_subscription_list",
  236. "featuresList: ${it.get(indexed).title} ${
  237. featuresListSortedData?.get(indexed)?.title
  238. }"
  239. )
  240. }
  241. }
  242. }
  243. }
  244. featuresListSorted.postValue(featuresListSortedData)
  245. featuresListSortedData.get(selectedPosition).features?.let {
  246. featuresListSortedItems.postValue(it)
  247. }
  248. val list = featuresListSorted.value
  249. Log.d("test_subscription_list", "featuresListSorted size = ${list?.size}")
  250. // featuresListSortedData.forEachIndexed { index, productFeatures ->
  251. // Log.d("test_subscription_list", "${productFeatures.title} + ${productFeatures.identifier} + ${productFeatures.price}")
  252. // }
  253. for ((index, value) in skuDetailsList.withIndex()) {
  254. // Log.d("test_subscription_list", value.title + " ," + value.freeTrialPeriod + "=>" + featuresList.value?.get(index)?.identifier)
  255. if (skuDetailsList.size > 1) {
  256. boolValue = index == 1
  257. } else {
  258. boolValue = index == 0
  259. }
  260. freePeriod = if (value.freeTrialPeriod == "P3D") {
  261. "Free for 3 days"
  262. } else if (value.freeTrialPeriod == "P1W") {
  263. "Free for 7 days"
  264. } else {
  265. ""
  266. }
  267. val planTitle = featuresListSortedData.get(index).title
  268. selectPriceListData.add(
  269. SubscriptionPackageList(
  270. planTitle ?: value.title, "Auto-Renewable", value.description, value.price,
  271. mutableStateOf(boolValue)
  272. )
  273. )
  274. }
  275. selectPriceListData.forEachIndexed { index, upgradePriceList ->
  276. Log.d(
  277. "test_subscription_list",
  278. "${upgradePriceList.packageDuration} ${upgradePriceList.planType} ${upgradePriceList.desc} ${upgradePriceList.price} ${upgradePriceList.isSelected.value}"
  279. )
  280. if (upgradePriceList.isSelected.value) {
  281. selectedPosition = index
  282. }
  283. }
  284. selectPriceList.postValue(selectPriceListData)
  285. }
  286. }
  287. override fun onPurchasesUpdated(p0: BillingResult, purchases: MutableList<Purchase>?) {
  288. if (purchases != null && purchases.size > 0) {
  289. Log.d("purchases_product", purchases.toString())
  290. parseDataAndMakeApiCall(purchases)
  291. }
  292. acknowledgePurchases(purchases)
  293. }
  294. private fun parseDataAndMakeApiCall(purchases: MutableList<Purchase>?) {
  295. try {
  296. val objectArray = JSONArray(Gson().toJson(purchases))
  297. val obj: JSONObject = objectArray.getJSONObject(0)
  298. val parsedJson = obj.getJSONObject("zzc")
  299. val nameValuePairs = parsedJson.getJSONObject("nameValuePairs")
  300. val orderId = nameValuePairs.getString("orderId")
  301. val productId = nameValuePairs.getString("productId")
  302. val packageName = nameValuePairs.getString("packageName")
  303. val purchaseToken = nameValuePairs.getString("purchaseToken")
  304. val billingCycle =
  305. productId.substring(productId.lastIndexOf('.') + 1) //removing pacakge name
  306. Log.d("purchases_product", billingCycle.toString())
  307. val receiptData = JSONObject()
  308. receiptData.put("orderId", orderId)
  309. receiptData.put("productId", productId)
  310. receiptData.put("packageName", packageName)
  311. receiptData.put("purchaseToken", purchaseToken)
  312. val receiptDataStr = receiptData.toString()
  313. val receiptDataStrEncoded: String =
  314. Base64.encodeToString(receiptDataStr.toByteArray(), Base64.NO_PADDING)
  315. create_subscription_Product(orderId, receiptDataStrEncoded, productId)
  316. // createOrder(billingCycle, orderId, receiptData)
  317. } catch (e: Exception) {
  318. e.printStackTrace()
  319. }
  320. }
  321. private fun create_subscription_Product(orderId: String, receiptData: String,
  322. productId: String) {
  323. Log.d("purchases_product", "$orderId, $receiptData, $productId")
  324. create_subscription(
  325. orderId, receiptData, productId
  326. )
  327. }
  328. private fun acknowledgePurchases(purchases: MutableList<Purchase>?) {
  329. val purchase = purchases?.first()
  330. if (purchase != null && !purchase.isAcknowledged
  331. && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
  332. val acknowledgePurchaseParams =
  333. AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.purchaseToken)
  334. .build()
  335. billingClient.acknowledgePurchase(acknowledgePurchaseParams) { billingResult ->
  336. if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
  337. Log.d(
  338. "purchases_product",
  339. "AcknowledgePurchases success, responseCode: ${billingResult.responseCode}"
  340. )
  341. } else {
  342. Log.d(
  343. "purchases_product",
  344. "Can't allowMultiplePurchases, responseCode: ${billingResult.responseCode}"
  345. )
  346. }
  347. }
  348. }
  349. }
  350. }