Fixes issue where GoPro button appears even if the user is subscribed

kmm
Laurent 5 years ago
parent 6c2367aa7f
commit eeaba2876a
  1. 22
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  2. 17
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt
  3. 33
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  4. 44
      app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt

@ -12,6 +12,7 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.android.billingclient.api.Purchase
import com.google.android.play.core.review.ReviewManagerFactory import com.google.android.play.core.review.ReviewManagerFactory
import io.realm.Realm import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.* 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.*
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts 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.csv.ProductCSVDescriptors
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import timber.log.Timber import timber.log.Timber
@ -45,7 +47,7 @@ import java.io.IOException
import java.util.* import java.util.*
class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource { class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource, PurchaseListener {
companion object { companion object {
@ -69,6 +71,16 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
private lateinit var settingsAdapterRow: RowRepresentableAdapter 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? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_settings, container, false) 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() {
}
} }

@ -32,12 +32,12 @@ import net.pokeranalytics.android.ui.fragment.components.ScreenSlidePageFragment
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts 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.lang.ref.WeakReference
import java.time.Period import java.time.Period
import java.time.format.DateTimeParseException import java.time.format.DateTimeParseException
class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseDelegate, ViewPager.OnPageChangeListener { class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseListener, ViewPager.OnPageChangeListener {
companion object { companion object {
val parallax: Float = 64f.px val parallax: Float = 64f.px
@ -67,6 +67,8 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
return return
} }
AppGuard.registerListener(this)
this.showLoader(R.string.loading_please_wait) this.showLoader(R.string.loading_please_wait)
if (!AppGuard.requestProducts(this)) { if (!AppGuard.requestProducts(this)) {
this.hideLoader() this.hideLoader()
@ -86,6 +88,11 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
initUI() initUI()
} }
override fun onDestroy() {
super.onDestroy()
AppGuard.unregisterListener(this)
}
private fun initData() { private fun initData() {
this.showSessionMessage = arguments?.getBoolean(BundleKey.SHOW_MESSAGE.value) ?: false this.showSessionMessage = arguments?.getBoolean(BundleKey.SHOW_MESSAGE.value) ?: false
} }
@ -133,7 +140,7 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
this.purchase.setOnClickListener { this.purchase.setOnClickListener {
this.selectedProduct?.let { this.selectedProduct?.let {
AppGuard.initiatePurchase(this.requireActivity(), it, this) AppGuard.initiatePurchase(this.requireActivity(), it)
} ?: run { } ?: run {
throw PAIllegalStateException("Attempt to initiate purchase while no product has been chosen") throw PAIllegalStateException("Attempt to initiate purchase while no product has been chosen")
} }
@ -236,6 +243,10 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
this.activity?.finish() this.activity?.finish()
} }
override fun noPurchaseRetrieved() {
}
// OnPageChangeListener // OnPageChangeListener
override fun onPageScrollStateChanged(state: Int) {} override fun onPageScrollStateChanged(state: Int) {}

@ -8,6 +8,7 @@ import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.android.billingclient.api.Purchase
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults 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.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.PurchaseListener
import net.pokeranalytics.android.util.extensions.count import net.pokeranalytics.android.util.extensions.count
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
class FeedFragment : FilterableFragment(), RowRepresentableDelegate { class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseListener {
private enum class Tab { private enum class Tab {
SESSIONS, SESSIONS,
@ -104,6 +106,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppGuard.registerListener(this)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -205,6 +212,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
} }
override fun onDestroy() {
AppGuard.unregisterListener(this)
super.onDestroy()
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
realmTransactions.removeAllChangeListeners() realmTransactions.removeAllChangeListeners()
@ -313,7 +325,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
this.showSubscriptionButton() this.showSubscriptionButton()
} }
} }
this.showSubscriptionButton()
} }
@ -419,11 +430,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
/** /**
* Create a new cash game * Create a new cash game
*/ */
private fun createNewSession( private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) {
isTournament: Boolean,
sessionId: String? = null,
duplicate: Boolean = false
) {
val sessionCount = getRealm().count(Session::class.java) val sessionCount = getRealm().count(Session::class.java)
if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG
@ -473,10 +480,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/ */
private fun createNewHandHistory() { private fun createNewHandHistory() {
// val intent = Intent(requireContext(), TestActivity::class.java)
// startActivity(intent)
// return
AppGuard.endOfUse?.let { endDate -> AppGuard.endOfUse?.let { endDate ->
if (Date().after(endDate)) { if (Date().after(endDate)) {
this.showEndOfUseMessage() this.showEndOfUseMessage()
@ -577,4 +580,12 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
this.sessionAdapter.notifyDataSetChanged() // refreshes session durations this.sessionAdapter.notifyDataSetChanged() // refreshes session durations
} }
override fun purchaseDidSucceed(purchase: Purchase) {
this.showSubscriptionButton()
}
override fun noPurchaseRetrieved() {
this.showSubscriptionButton()
}
} }

@ -18,8 +18,9 @@ enum class IAPProducts(var identifier: String) {
PRO("unlimited") PRO("unlimited")
} }
interface PurchaseDelegate { interface PurchaseListener {
fun purchaseDidSucceed(purchase: Purchase) fun purchaseDidSucceed(purchase: Purchase)
fun noPurchaseRetrieved()
} }
/** /**
@ -61,6 +62,8 @@ object AppGuard : PurchasesUpdatedListener {
*/ */
val isProUser: Boolean val isProUser: Boolean
get() { get() {
return this._isProUser
if (this.endOfUse != null) return true if (this.endOfUse != null) return true
@ -93,7 +96,7 @@ object AppGuard : PurchasesUpdatedListener {
/** /**
* A delegate to notify when the purchase has succeeded * A delegate to notify when the purchase has succeeded
*/ */
private var purchaseDelegate: PurchaseDelegate? = null private var purchaseListeners: MutableList<PurchaseListener> = mutableListOf()
/** /**
* Initialization of AppGuard * Initialization of AppGuard
@ -206,9 +209,7 @@ object AppGuard : PurchasesUpdatedListener {
/** /**
* Initiates purchase with the product [skuDetails] * Initiates purchase with the product [skuDetails]
*/ */
fun initiatePurchase(activity: Activity, skuDetails: SkuDetails, delegate: PurchaseDelegate) { fun initiatePurchase(activity: Activity, skuDetails: SkuDetails) {
this.purchaseDelegate = delegate
val flowParams = BillingFlowParams.newBuilder() val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails) .setSkuDetails(skuDetails)
@ -225,10 +226,14 @@ object AppGuard : PurchasesUpdatedListener {
override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) { override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
if (result.responseCode == BillingResponseCode.OK && purchases != null) { if (result.responseCode == BillingResponseCode.OK) {
if (purchases != null && purchases.isNotEmpty()) {
for (purchase in purchases) { for (purchase in purchases) {
handlePurchase(purchase) handlePurchase(purchase)
} }
} else {
sendNoPurchaseRetrievedEvent()
}
} else if (result.responseCode == BillingResponseCode.USER_CANCELED) { } else if (result.responseCode == BillingResponseCode.USER_CANCELED) {
Timber.d("purchase cancel message: ${result.debugMessage}") Timber.d("purchase cancel message: ${result.debugMessage}")
// Handle an error caused by a user cancelling the purchase flow. // Handle an error caused by a user cancelling the purchase flow.
@ -240,6 +245,12 @@ object AppGuard : PurchasesUpdatedListener {
} }
private fun sendNoPurchaseRetrievedEvent() {
this.purchaseListeners.forEach { listener ->
listener.noPurchaseRetrieved()
}
}
// /** // /**
// * Purchase callback // * Purchase callback
// */ // */
@ -280,12 +291,13 @@ object AppGuard : PurchasesUpdatedListener {
} }
this._isProUser = true this._isProUser = true
this.purchaseDelegate?.let {
this.purchaseListeners.forEach { listener ->
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
it.purchaseDidSucceed(purchase) listener.purchaseDidSucceed(purchase)
} }
this.purchaseDelegate = null
} }
} }
} }
@ -318,4 +330,18 @@ object AppGuard : PurchasesUpdatedListener {
return context.getString(resId) 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)
}
} }
Loading…
Cancel
Save