diff --git a/mobile/build.gradle b/mobile/build.gradle index 00ce931e..e78eac93 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -86,7 +86,7 @@ dependencies { implementation 'androidx.preference:preference:1.1.0' implementation "androidx.room:room-ktx:$roomVersion" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'com.android.billingclient:billing:2.0.3' + implementation 'com.android.billingclient:billing-ktx:2.1.0' implementation 'com.github.topjohnwu.libsu:core:2.5.1' implementation 'com.google.android.material:material:1.1.0-beta02' implementation 'com.google.zxing:core:3.4.0' @@ -95,7 +95,7 @@ dependencies { implementation 'com.takisoft.preferencex:preferencex-simplemenu:1.1.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" implementation 'org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2-1.3.60' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' for (dep in aux) { freedomImplementation dep googleImplementation dep diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt index f8c361f0..6cbab492 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt @@ -8,18 +8,22 @@ import android.widget.ArrayAdapter import android.widget.Button import android.widget.Spinner import androidx.appcompat.app.AppCompatDialogFragment +import androidx.lifecycle.lifecycleScope import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.util.launchUrl import be.mygod.vpnhotspot.widget.SmartSnackbar import com.android.billingclient.api.* import kotlinx.android.synthetic.main.fragment_ebeg.view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import timber.log.Timber /** * Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java */ -class EBegFragment : AppCompatDialogFragment(), SkuDetailsResponseListener { - companion object : BillingClientStateListener, PurchasesUpdatedListener, ConsumeResponseListener { +class EBegFragment : AppCompatDialogFragment() { + companion object : BillingClientStateListener, PurchasesUpdatedListener { private lateinit var billingClient: BillingClient fun init() { @@ -46,23 +50,23 @@ class EBegFragment : AppCompatDialogFragment(), SkuDetailsResponseListener { override fun onPurchasesUpdated(billingResult: BillingResult?, purchases: MutableList?) { if (billingResult?.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) { // directly consume in-app purchase, so that people can donate multiple times - for (purchase in purchases) if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) { - billingClient.consumeAsync(ConsumeParams.newBuilder().apply { - setPurchaseToken(purchase.purchaseToken) - }.build(), this) - } + purchases.filter { it.purchaseState == Purchase.PurchaseState.PURCHASED }.map(this::consumePurchase) } else Timber.e("onPurchasesUpdated: ${billingResult?.responseCode}") } - override fun onConsumeResponse(billingResult: BillingResult?, purchaseToken: String?) { - if (billingResult?.responseCode == BillingClient.BillingResponseCode.OK) { - SmartSnackbar.make(R.string.donations__thanks_dialog).show() - } else Timber.e("onConsumeResponse: ${billingResult?.responseCode}") + private fun consumePurchase(purchase: Purchase) = GlobalScope.launch(Dispatchers.Main.immediate) { + billingClient.consumePurchase(ConsumeParams.newBuilder().apply { + setPurchaseToken(purchase.purchaseToken) + }.build()).apply { + if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { + SmartSnackbar.make(R.string.donations__thanks_dialog).show() + } else Timber.e("onConsumeResponse: ${billingResult.responseCode}") + } } } private lateinit var googleSpinner: Spinner - private var skus: MutableList? = null + private var skus: List? = null set(value) { field = value googleSpinner.apply { @@ -79,12 +83,18 @@ class EBegFragment : AppCompatDialogFragment(), SkuDetailsResponseListener { super.onViewCreated(view, savedInstanceState) dialog!!.setTitle(R.string.settings_misc_donate) googleSpinner = view.donations__google_android_market_spinner - billingClient.querySkuDetailsAsync( - SkuDetailsParams.newBuilder().apply { - setSkusList(listOf("donate001", "donate002", "donate005", "donate010", "donate020", "donate050", - "donate100", "donate200", "donatemax")) - setType(BillingClient.SkuType.INAPP) - }.build(), this) + lifecycleScope.launchWhenCreated { + billingClient.querySkuDetails(SkuDetailsParams.newBuilder().apply { + setSkusList(listOf("donate001", "donate002", "donate005", "donate010", "donate020", "donate050", + "donate100", "donate200", "donatemax")) + setType(BillingClient.SkuType.INAPP) + }.build()).apply { + if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) skus = skuDetailsList else { + Timber.e("onSkuDetailsResponse: ${billingResult.responseCode}") + SmartSnackbar.make(R.string.donations__google_android_market_not_supported).show() + } + } + } view.donations__google_android_market_donate_button.setOnClickListener { val sku = skus?.getOrNull(googleSpinner.selectedItemPosition) if (sku != null) billingClient.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().apply { @@ -95,11 +105,4 @@ class EBegFragment : AppCompatDialogFragment(), SkuDetailsResponseListener { if (BuildConfig.DONATIONS) (view.donations__more_stub.inflate() as Button) .setOnClickListener { requireContext().launchUrl("https://mygod.be/donate/") } } - - override fun onSkuDetailsResponse(billingResult: BillingResult?, skuDetailsList: MutableList?) { - if (billingResult?.responseCode == BillingClient.BillingResponseCode.OK) skus = skuDetailsList else { - Timber.e("onSkuDetailsResponse: ${billingResult?.responseCode}") - SmartSnackbar.make(R.string.donations__google_android_market_not_supported).show() - } - } }