Auto commit (MindMachine) Wed Apr 15 10:01:01 PM CDT 2026

This commit is contained in:
Tretzi
2026-04-15 22:01:01 -05:00
parent 011e4ba349
commit 937689cbfa
3 changed files with 67 additions and 28 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId = "solutions.tretter.mindmachine" applicationId = "solutions.tretter.mindmachine"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 35
versionCode = 7 versionCode = 11
versionName = "1.0.2" versionName = "1.0.6"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -9,7 +9,8 @@ import com.android.billingclient.api.BillingClientStateListener
import com.android.billingclient.api.BillingFlowParams import com.android.billingclient.api.BillingFlowParams
import com.android.billingclient.api.BillingResult import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ProductDetails 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.Purchase
import com.android.billingclient.api.PurchasesResponseListener import com.android.billingclient.api.PurchasesResponseListener
import com.android.billingclient.api.QueryProductDetailsParams 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.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import android.os.Handler
import android.os.Looper
class BillingManager( class BillingManager(
context: Context, context: Context,
@@ -44,30 +47,50 @@ class BillingManager(
handlePurchases(purchases) handlePurchases(purchases)
} }
} }
.enablePendingPurchases() .enablePendingPurchases(
PendingPurchasesParams.newBuilder()
.enableOneTimeProducts()
.build()
)
.build() .build()
@Volatile
private var isConnecting = false
fun start() { fun start() {
log("BillingManager.start() - isReady=${billingClient.isReady}") log("BillingManager.start() - isReady=${billingClient.isReady}, isConnecting=$isConnecting")
if (billingClient.isReady) { if (billingClient.isReady) {
log("Billing client already ready") log("Billing client already ready")
refresh() refresh()
return return
} }
if (isConnecting) {
log("Billing client connection already in progress")
return
}
isConnecting = true
log("Calling startConnection()")
billingClient.startConnection(object : BillingClientStateListener { billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(result: BillingResult) { override fun onBillingSetupFinished(result: BillingResult) {
isConnecting = false
log("Billing setup finished: ${result.responseCode} ${result.debugMessage}") log("Billing setup finished: ${result.responseCode} ${result.debugMessage}")
if (result.responseCode == BillingClient.BillingResponseCode.OK) { if (result.responseCode == BillingClient.BillingResponseCode.OK) {
refresh() Handler(Looper.getMainLooper()).post {
refresh()
}
} else { } else {
logError("Billing setup failed: ${result.responseCode} ${result.debugMessage}") logError("Billing setup failed: ${result.responseCode} ${result.debugMessage}")
} }
} }
override fun onBillingServiceDisconnected() { override fun onBillingServiceDisconnected() {
log("Billing service disconnected - attempting reconnect") isConnecting = false
// Auto-reconnection handled by billing client, retry connection log("Billing service disconnected")
start()
} }
}) })
} }
@@ -132,36 +155,52 @@ class BillingManager(
return return
} }
// Check if product details feature is supported
val featureResult = billingClient.isFeatureSupported(BillingClient.FeatureType.PRODUCT_DETAILS) val featureResult = billingClient.isFeatureSupported(BillingClient.FeatureType.PRODUCT_DETAILS)
log("PRODUCT_DETAILS support: ${featureResult.responseCode} ${featureResult.debugMessage}")
if (featureResult.responseCode != BillingClient.BillingResponseCode.OK) { if (featureResult.responseCode != BillingClient.BillingResponseCode.OK) {
logError("PRODUCT_DETAILS feature not supported: ${featureResult.responseCode}") logError("PRODUCT_DETAILS feature not supported")
return 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() QueryProductDetailsParams.Product.newBuilder()
.setProductId(BillingProducts.SUB_REMOVE_ADS_MONTHLY) .setProductId(id)
.setProductType(BillingClient.ProductType.SUBS) .setProductType(type)
.build(), .build()
QueryProductDetailsParams.Product.newBuilder() }
.setProductId(BillingProducts.INAPP_REMOVE_ADS_FOREVER)
.setProductType(BillingClient.ProductType.INAPP) log(
.build(), "Querying product details for: " +
"${BillingProducts.SUB_REMOVE_ADS_MONTHLY}:${BillingClient.ProductType.SUBS}, " +
"${BillingProducts.INAPP_REMOVE_ADS_FOREVER}:${BillingClient.ProductType.INAPP}"
) )
val params = QueryProductDetailsParams.newBuilder() val params = QueryProductDetailsParams.newBuilder()
.setProductList(products) .setProductList(products)
.build() .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) { if (result.responseCode == BillingClient.BillingResponseCode.OK) {
log("Product details loaded: ${detailsList.size} items")
_productDetails.value = detailsList.associateBy { it.productId } _productDetails.value = detailsList.associateBy { it.productId }
} else {
logError("queryProductDetails failed: ${result.responseCode} ${result.debugMessage}")
} }
}) }
} }
private fun queryActivePurchases() { private fun queryActivePurchases() {