From eeaba2876a0165fa5b808978cd0d29b42c7a5963 Mon Sep 17 00:00:00 2001 From: Laurent Date: Fri, 2 Oct 2020 12:20:51 +0200 Subject: [PATCH] Fixes issue where GoPro button appears even if the user is subscribed --- .../android/ui/fragment/SettingsFragment.kt | 22 ++++++++- .../ui/fragment/SubscriptionFragment.kt | 17 +++++-- .../android/ui/modules/feed/FeedFragment.kt | 33 ++++++++----- .../android/util/billing/AppGuard.kt | 48 ++++++++++++++----- 4 files changed, 94 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt index 111cee96..4e55ea8d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt @@ -12,6 +12,7 @@ import android.view.ViewGroup import android.widget.Toast import androidx.core.content.FileProvider import androidx.recyclerview.widget.LinearLayoutManager +import com.android.billingclient.api.Purchase import com.google.android.play.core.review.ReviewManagerFactory import io.realm.Realm import kotlinx.android.synthetic.main.fragment_settings.* @@ -37,6 +38,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow import net.pokeranalytics.android.util.* import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.IAPProducts +import net.pokeranalytics.android.util.billing.PurchaseListener import net.pokeranalytics.android.util.csv.ProductCSVDescriptors import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted import timber.log.Timber @@ -45,7 +47,7 @@ import java.io.IOException import java.util.* -class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource { +class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource, PurchaseListener { companion object { @@ -69,6 +71,16 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep private lateinit var settingsAdapterRow: RowRepresentableAdapter + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + AppGuard.registerListener(this) + } + + override fun onDestroy() { + super.onDestroy() + AppGuard.unregisterListener(this) + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_settings, container, false) @@ -299,4 +311,12 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep } + override fun purchaseDidSucceed(purchase: Purchase) { + this.settingsAdapterRow.refreshRow(SettingRow.SUBSCRIPTION) + } + + override fun noPurchaseRetrieved() { + + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt index 503464c1..88fcd6ec 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt @@ -32,12 +32,12 @@ import net.pokeranalytics.android.ui.fragment.components.ScreenSlidePageFragment import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.IAPProducts -import net.pokeranalytics.android.util.billing.PurchaseDelegate +import net.pokeranalytics.android.util.billing.PurchaseListener import java.lang.ref.WeakReference import java.time.Period import java.time.format.DateTimeParseException -class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseDelegate, ViewPager.OnPageChangeListener { +class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseListener, ViewPager.OnPageChangeListener { companion object { val parallax: Float = 64f.px @@ -67,6 +67,8 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas return } + AppGuard.registerListener(this) + this.showLoader(R.string.loading_please_wait) if (!AppGuard.requestProducts(this)) { this.hideLoader() @@ -86,6 +88,11 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas initUI() } + override fun onDestroy() { + super.onDestroy() + AppGuard.unregisterListener(this) + } + private fun initData() { this.showSessionMessage = arguments?.getBoolean(BundleKey.SHOW_MESSAGE.value) ?: false } @@ -133,7 +140,7 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas this.purchase.setOnClickListener { this.selectedProduct?.let { - AppGuard.initiatePurchase(this.requireActivity(), it, this) + AppGuard.initiatePurchase(this.requireActivity(), it) } ?: run { throw PAIllegalStateException("Attempt to initiate purchase while no product has been chosen") } @@ -236,6 +243,10 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas this.activity?.finish() } + override fun noPurchaseRetrieved() { + + } + // OnPageChangeListener override fun onPageScrollStateChanged(state: Int) {} diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt index daeb7ce5..c9f3b386 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt @@ -8,6 +8,7 @@ import android.widget.Toast import androidx.core.app.ActivityOptionsCompat import androidx.core.view.isVisible import androidx.interpolator.view.animation.FastOutSlowInInterpolator +import com.android.billingclient.api.Purchase import com.google.android.material.tabs.TabLayout import io.realm.RealmModel import io.realm.RealmResults @@ -37,11 +38,12 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.billing.AppGuard +import net.pokeranalytics.android.util.billing.PurchaseListener import net.pokeranalytics.android.util.extensions.count import timber.log.Timber import java.util.* -class FeedFragment : FilterableFragment(), RowRepresentableDelegate { +class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseListener { private enum class Tab { SESSIONS, @@ -104,6 +106,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + AppGuard.registerListener(this) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -205,6 +212,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { } + override fun onDestroy() { + AppGuard.unregisterListener(this) + super.onDestroy() + } + override fun onDestroyView() { super.onDestroyView() realmTransactions.removeAllChangeListeners() @@ -313,7 +325,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { this.showSubscriptionButton() } } - this.showSubscriptionButton() } @@ -419,11 +430,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { /** * Create a new cash game */ - private fun createNewSession( - isTournament: Boolean, - sessionId: String? = null, - duplicate: Boolean = false - ) { + private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) { val sessionCount = getRealm().count(Session::class.java) if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG @@ -473,10 +480,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { */ private fun createNewHandHistory() { -// val intent = Intent(requireContext(), TestActivity::class.java) -// startActivity(intent) -// return - AppGuard.endOfUse?.let { endDate -> if (Date().after(endDate)) { this.showEndOfUseMessage() @@ -577,4 +580,12 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { this.sessionAdapter.notifyDataSetChanged() // refreshes session durations } + override fun purchaseDidSucceed(purchase: Purchase) { + this.showSubscriptionButton() + } + + override fun noPurchaseRetrieved() { + this.showSubscriptionButton() + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt b/app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt index 6ab05e33..5d5eb840 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt @@ -18,8 +18,9 @@ enum class IAPProducts(var identifier: String) { PRO("unlimited") } -interface PurchaseDelegate { +interface PurchaseListener { fun purchaseDidSucceed(purchase: Purchase) + fun noPurchaseRetrieved() } /** @@ -61,6 +62,8 @@ object AppGuard : PurchasesUpdatedListener { */ val isProUser: Boolean get() { + return this._isProUser + if (this.endOfUse != null) return true @@ -93,7 +96,7 @@ object AppGuard : PurchasesUpdatedListener { /** * A delegate to notify when the purchase has succeeded */ - private var purchaseDelegate: PurchaseDelegate? = null + private var purchaseListeners: MutableList = mutableListOf() /** * Initialization of AppGuard @@ -206,9 +209,7 @@ object AppGuard : PurchasesUpdatedListener { /** * Initiates purchase with the product [skuDetails] */ - fun initiatePurchase(activity: Activity, skuDetails: SkuDetails, delegate: PurchaseDelegate) { - - this.purchaseDelegate = delegate + fun initiatePurchase(activity: Activity, skuDetails: SkuDetails) { val flowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) @@ -225,9 +226,13 @@ object AppGuard : PurchasesUpdatedListener { override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList?) { - if (result.responseCode == BillingResponseCode.OK && purchases != null) { - for (purchase in purchases) { - handlePurchase(purchase) + if (result.responseCode == BillingResponseCode.OK) { + if (purchases != null && purchases.isNotEmpty()) { + for (purchase in purchases) { + handlePurchase(purchase) + } + } else { + sendNoPurchaseRetrievedEvent() } } else if (result.responseCode == BillingResponseCode.USER_CANCELED) { Timber.d("purchase cancel message: ${result.debugMessage}") @@ -240,6 +245,12 @@ object AppGuard : PurchasesUpdatedListener { } + private fun sendNoPurchaseRetrievedEvent() { + this.purchaseListeners.forEach { listener -> + listener.noPurchaseRetrieved() + } + } + // /** // * Purchase callback // */ @@ -280,12 +291,13 @@ object AppGuard : PurchasesUpdatedListener { } this._isProUser = true - this.purchaseDelegate?.let { + + this.purchaseListeners.forEach { listener -> Handler(Looper.getMainLooper()).post { - it.purchaseDidSucceed(purchase) + listener.purchaseDidSucceed(purchase) } - this.purchaseDelegate = null } + } } @@ -318,4 +330,18 @@ object AppGuard : PurchasesUpdatedListener { return context.getString(resId) } + /*** + * Removes a listener + */ + fun registerListener(listener: PurchaseListener) { + this.purchaseListeners.add(listener) + } + + /*** + * Removes a listener + */ + fun unregisterListener(listener: PurchaseListener) { + this.purchaseListeners.remove(listener) + } + } \ No newline at end of file