From 937689cbfa2ec152eb8ba3a1be899d3ae068e039 Mon Sep 17 00:00:00 2001 From: Tretzi Date: Wed, 15 Apr 2026 22:01:01 -0500 Subject: [PATCH] Auto commit (MindMachine) Wed Apr 15 10:01:01 PM CDT 2026 --- app/build.gradle.kts | 4 +- .../mvp/billing/.BillingManager.kt.swp | Bin 20480 -> 0 bytes .../mindmachine/mvp/billing/BillingManager.kt | 91 +++++++++++++----- 3 files changed, 67 insertions(+), 28 deletions(-) delete mode 100644 app/src/main/java/com/mindmachine/mvp/billing/.BillingManager.kt.swp diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5e70723..cc95807 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { applicationId = "solutions.tretter.mindmachine" minSdk = 26 targetSdk = 35 - versionCode = 7 - versionName = "1.0.2" + versionCode = 11 + versionName = "1.0.6" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/mindmachine/mvp/billing/.BillingManager.kt.swp b/app/src/main/java/com/mindmachine/mvp/billing/.BillingManager.kt.swp deleted file mode 100644 index c7eaa0af1d7fbd29b629c58347e75a5370222c88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 diff --git a/app/src/main/java/com/mindmachine/mvp/billing/BillingManager.kt b/app/src/main/java/com/mindmachine/mvp/billing/BillingManager.kt index 6d0ae51..91606b9 100644 --- a/app/src/main/java/com/mindmachine/mvp/billing/BillingManager.kt +++ b/app/src/main/java/com/mindmachine/mvp/billing/BillingManager.kt @@ -9,7 +9,8 @@ import com.android.billingclient.api.BillingClientStateListener import com.android.billingclient.api.BillingFlowParams import com.android.billingclient.api.BillingResult import com.android.billingclient.api.ProductDetails -import com.android.billingclient.api.ProductDetailsResponseListener +import com.android.billingclient.api.QueryProductDetailsResult +import com.android.billingclient.api.PendingPurchasesParams import com.android.billingclient.api.Purchase import com.android.billingclient.api.PurchasesResponseListener import com.android.billingclient.api.QueryProductDetailsParams @@ -17,6 +18,8 @@ import com.android.billingclient.api.QueryPurchasesParams import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import android.os.Handler +import android.os.Looper class BillingManager( context: Context, @@ -44,30 +47,50 @@ class BillingManager( handlePurchases(purchases) } } - .enablePendingPurchases() + .enablePendingPurchases( + PendingPurchasesParams.newBuilder() + .enableOneTimeProducts() + .build() + ) .build() + @Volatile + private var isConnecting = false + fun start() { - log("BillingManager.start() - isReady=${billingClient.isReady}") + log("BillingManager.start() - isReady=${billingClient.isReady}, isConnecting=$isConnecting") + if (billingClient.isReady) { log("Billing client already ready") refresh() return } + + if (isConnecting) { + log("Billing client connection already in progress") + return + } + + isConnecting = true + log("Calling startConnection()") + billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(result: BillingResult) { + isConnecting = false log("Billing setup finished: ${result.responseCode} ${result.debugMessage}") + if (result.responseCode == BillingClient.BillingResponseCode.OK) { - refresh() + Handler(Looper.getMainLooper()).post { + refresh() + } } else { logError("Billing setup failed: ${result.responseCode} ${result.debugMessage}") } } - + override fun onBillingServiceDisconnected() { - log("Billing service disconnected - attempting reconnect") - // Auto-reconnection handled by billing client, retry connection - start() + isConnecting = false + log("Billing service disconnected") } }) } @@ -131,37 +154,53 @@ class BillingManager( log("Billing client not ready") return } - - // Check if product details feature is supported + val featureResult = billingClient.isFeatureSupported(BillingClient.FeatureType.PRODUCT_DETAILS) + log("PRODUCT_DETAILS support: ${featureResult.responseCode} ${featureResult.debugMessage}") if (featureResult.responseCode != BillingClient.BillingResponseCode.OK) { - logError("PRODUCT_DETAILS feature not supported: ${featureResult.responseCode}") + logError("PRODUCT_DETAILS feature not supported") return } - - val products = listOf( + + val requestedProducts = listOf( + BillingProducts.SUB_REMOVE_ADS_MONTHLY to BillingClient.ProductType.SUBS, + BillingProducts.INAPP_REMOVE_ADS_FOREVER to BillingClient.ProductType.INAPP, + ) + + log("Querying product details for: $requestedProducts") + + val products = requestedProducts.map { (id, type) -> QueryProductDetailsParams.Product.newBuilder() - .setProductId(BillingProducts.SUB_REMOVE_ADS_MONTHLY) - .setProductType(BillingClient.ProductType.SUBS) - .build(), - QueryProductDetailsParams.Product.newBuilder() - .setProductId(BillingProducts.INAPP_REMOVE_ADS_FOREVER) - .setProductType(BillingClient.ProductType.INAPP) - .build(), + .setProductId(id) + .setProductType(type) + .build() + } + + log( + "Querying product details for: " + + "${BillingProducts.SUB_REMOVE_ADS_MONTHLY}:${BillingClient.ProductType.SUBS}, " + + "${BillingProducts.INAPP_REMOVE_ADS_FOREVER}:${BillingClient.ProductType.INAPP}" ) val params = QueryProductDetailsParams.newBuilder() .setProductList(products) .build() - - billingClient.queryProductDetailsAsync(params, ProductDetailsResponseListener { result, detailsList -> + + log("Calling queryProductDetailsAsync now") + + billingClient.queryProductDetailsAsync(params) { result, queryResult -> + log("queryProductDetails result: ${result.responseCode} ${result.debugMessage}") + + val detailsList = queryResult.productDetailsList + log("Fetched products: ${detailsList.map { it.productId }}") + + val unfetched = queryResult.unfetchedProductList + log("Unfetched products: ${unfetched.map { "${it.productId}:${it.statusCode}" }}") + if (result.responseCode == BillingClient.BillingResponseCode.OK) { - log("Product details loaded: ${detailsList.size} items") _productDetails.value = detailsList.associateBy { it.productId } - } else { - logError("queryProductDetails failed: ${result.responseCode} ${result.debugMessage}") } - }) + } } private fun queryActivePurchases() {