From 1cba3d30681ec4d17c7dbad365d26ae98781408c Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Sun, 30 Dec 2018 19:44:37 +0100 Subject: [PATCH] Fix gifting subscription flow --- Habitica/res/values/strings.xml | 6 +- .../habitica/HabiticaBaseApplication.kt | 2 +- .../habitica/HabiticaPurchaseVerifier.java | 9 ++- .../data/implementation/ApiClientImpl.kt | 2 +- .../events/ConsumablePurchasedEvent.kt | 5 ++ .../habitica/ui/activities/BaseActivity.kt | 8 +- .../ui/activities/GemPurchaseActivity.kt | 55 +++++++++----- .../habitica/ui/activities/GiftIAPActivity.kt | 73 +++++++++++++++---- 8 files changed, 118 insertions(+), 42 deletions(-) create mode 100644 Habitica/src/main/java/com/habitrpg/android/habitica/events/ConsumablePurchasedEvent.kt diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml index 5baaf583e..9f30c1093 100644 --- a/Habitica/res/values/strings.xml +++ b/Habitica/res/values/strings.xml @@ -848,8 +848,12 @@ Gift a sub and get a sub free event going on now! Who would you like to gift to? Gift one, Get one! - While this promotion is active, you’ll receive a matching subscription automatically after sending your gift. + While this promotion is active, you’ll receive a matching subscription automatically after sending your gift. Choose the subscription you’d like to gift below! This purchase won’t automatically renew. Send Gift Server + Your gift was sent! + Your gifted subscription was sent and your subscription applied to your account. + Your gifted subscription was sent and your subscription applied to your account. + diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt index c80872dd5..97fa85347 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -226,7 +226,7 @@ abstract class HabiticaBaseApplication : MultiDexApplication() { } fun checkUserAuthentication(context: Context, hostConfig: HostConfig?): Boolean { - if (hostConfig == null || hostConfig.api == null || hostConfig.api == "" || hostConfig.user == null || hostConfig.user == "") { + if (hostConfig?.api == null || hostConfig.api == "" || hostConfig.user == "") { startActivity(IntroActivity::class.java, context) return false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java index 1d70a6c4f..19b228300 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaPurchaseVerifier.java @@ -3,9 +3,9 @@ package com.habitrpg.android.habitica; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import androidx.annotation.NonNull; import com.habitrpg.android.habitica.data.ApiClient; +import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent; import com.habitrpg.android.habitica.events.UserSubscribedEvent; import com.habitrpg.android.habitica.helpers.PurchaseTypes; import com.habitrpg.android.habitica.models.IAPGift; @@ -13,6 +13,7 @@ import com.habitrpg.android.habitica.models.PurchaseValidationRequest; import com.habitrpg.android.habitica.models.SubscriptionValidationRequest; import com.habitrpg.android.habitica.models.Transaction; import com.habitrpg.android.habitica.models.responses.ErrorResponse; +import com.habitrpg.android.habitica.proxy.CrashlyticsProxy; import com.playseeds.android.sdk.Seeds; import org.greenrobot.eventbus.EventBus; @@ -30,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import androidx.annotation.NonNull; import retrofit2.HttpException; /** @@ -79,7 +81,7 @@ public class HabiticaPurchaseVerifier extends BasePurchaseVerifier { purchasedOrderList.add(purchase.orderId); requestListener.onSuccess(verifiedPurchases); - + EventBus.getDefault().post(new ConsumablePurchasedEvent(purchase)); //TODO: find way to get $ price automatically. if (purchase.sku.equals(PurchaseTypes.Purchase4Gems)) { @@ -100,6 +102,7 @@ public class HabiticaPurchaseVerifier extends BasePurchaseVerifier { purchasedOrderList.add(purchase.orderId); requestListener.onSuccess(verifiedPurchases); + EventBus.getDefault().post(new ConsumablePurchasedEvent(purchase)); return; } } @@ -124,6 +127,7 @@ public class HabiticaPurchaseVerifier extends BasePurchaseVerifier { pendingGifts.remove(purchase.sku); } requestListener.onSuccess(verifiedPurchases); + EventBus.getDefault().post(new ConsumablePurchasedEvent(purchase)); }, throwable -> { if (throwable.getClass().equals(retrofit2.adapter.rxjava2.HttpException.class)) { HttpException error = (HttpException)throwable; @@ -133,6 +137,7 @@ public class HabiticaPurchaseVerifier extends BasePurchaseVerifier { purchasedOrderList.add(purchase.orderId); requestListener.onSuccess(verifiedPurchases); + EventBus.getDefault().post(new ConsumablePurchasedEvent(purchase)); return; } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index 42598ec2b..01080814c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -250,7 +250,7 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; } override fun hasAuthenticationKeys(): Boolean { - return this.hostConfig.user != null + return this.hostConfig.user.isNotEmpty() && hostConfig.api.isNotEmpty() } private fun showConnectionProblemDialog(resourceMessageString: Int) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/ConsumablePurchasedEvent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ConsumablePurchasedEvent.kt new file mode 100644 index 000000000..b8ed8dd0a --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/events/ConsumablePurchasedEvent.kt @@ -0,0 +1,5 @@ +package com.habitrpg.android.habitica.events + +import org.solovyev.android.checkout.Purchase + +class ConsumablePurchasedEvent(internal val purchase: Purchase) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt index 44e70bd7e..78084dc7d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt @@ -1,9 +1,7 @@ package com.habitrpg.android.habitica.ui.activities -import android.content.Intent -import android.os.Build import android.os.Bundle -import android.provider.Settings +import android.view.MotionEvent import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar @@ -12,12 +10,10 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.events.ShowConnectionProblemEvent +import com.instabug.library.InstabugTrackingDelegate import io.reactivex.disposables.CompositeDisposable import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe -import com.instabug.library.InstabugTrackingDelegate -import android.view.MotionEvent - abstract class BaseActivity : AppCompatActivity() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt index c71cbcc39..da8e9328a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt @@ -12,6 +12,7 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.PurchaseTypes import com.habitrpg.android.habitica.helpers.RxErrorHandler @@ -23,6 +24,7 @@ import com.habitrpg.android.habitica.ui.helpers.bindView import com.playseeds.android.sdk.Seeds import com.playseeds.android.sdk.inappmessaging.InAppMessageListener import io.reactivex.functions.Consumer +import org.greenrobot.eventbus.Subscribe import org.solovyev.android.checkout.* import java.util.* import javax.inject.Inject @@ -38,6 +40,7 @@ class GemPurchaseActivity : BaseActivity(), InAppMessageListener { internal val viewPager: androidx.viewpager.widget.ViewPager by bindView(R.id.viewPager) internal var fragments: MutableList = ArrayList() + var isActive = false var activityCheckout: ActivityCheckout? = null private set private var billingRequests: BillingRequests? = null @@ -91,28 +94,15 @@ class GemPurchaseActivity : BaseActivity(), InAppMessageListener { }, RxErrorHandler.handleEmptyError())) } - override fun onResume() { - super.onResume() + override fun onStart() { + super.onStart() setupCheckout() activityCheckout?.destroyPurchaseFlow() activityCheckout?.createPurchaseFlow(object : RequestListener { override fun onSuccess(purchase: Purchase) { - if (PurchaseTypes.allGemTypes.contains(purchase.sku) || PurchaseTypes.allSubscriptionNoRenewTypes.contains(purchase.sku)) { - billingRequests?.consume(purchase.token, object : RequestListener { - override fun onSuccess(o: Any) { - //EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD)); - if (purchase.sku == PurchaseTypes.Purchase84Gems) { - this@GemPurchaseActivity.showSeedsPromo(getString(R.string.seeds_interstitial_sharing), "store") - } - } - override fun onError(i: Int, e: Exception) { - crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e) - } - }) - } } override fun onError(i: Int, e: Exception) { @@ -140,9 +130,19 @@ class GemPurchaseActivity : BaseActivity(), InAppMessageListener { }) } - public override fun onPause() { - activityCheckout?.stop() + override fun onResume() { + super.onResume() + isActive = true + } + + override fun onPause() { super.onPause() + isActive = false + } + + public override fun onStop() { + activityCheckout?.stop() + super.onStop() } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -270,6 +270,13 @@ class GemPurchaseActivity : BaseActivity(), InAppMessageListener { }) } + @Subscribe + public fun onConsumablePurchased(event: ConsumablePurchasedEvent) { + if (isActive) { + consumePurchase(event.purchase) + } + } + interface CheckoutFragment { fun setupCheckout() @@ -279,4 +286,18 @@ class GemPurchaseActivity : BaseActivity(), InAppMessageListener { fun setBillingRequests(billingRequests: BillingRequests?) } + private fun consumePurchase(purchase: Purchase) { + if (PurchaseTypes.allGemTypes.contains(purchase.sku) || PurchaseTypes.allSubscriptionNoRenewTypes.contains(purchase.sku)) { + billingRequests?.consume(purchase.token, object : RequestListener { + + override fun onSuccess(result: Any) { + + } + + override fun onError(response: Int, e: Exception) { + crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e) + } + }) + } + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt index 7badf3b47..3ae359750 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt @@ -1,12 +1,14 @@ package com.habitrpg.android.habitica.ui.activities -import android.content.Context +import android.content.Intent +import android.os.Build import android.os.Bundle -import android.util.AttributeSet +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.TextView +import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.Toolbar import androidx.core.view.isVisible import com.habitrpg.android.habitica.HabiticaBaseApplication @@ -14,6 +16,7 @@ import com.habitrpg.android.habitica.HabiticaPurchaseVerifier import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.PurchaseTypes import com.habitrpg.android.habitica.helpers.RemoteConfigManager @@ -25,11 +28,9 @@ import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView import io.reactivex.functions.Consumer +import org.greenrobot.eventbus.Subscribe import org.solovyev.android.checkout.* import javax.inject.Inject -import android.content.Intent - - class GiftIAPActivity: BaseActivity() { @@ -100,9 +101,8 @@ class GiftIAPActivity: BaseActivity() { }, RxErrorHandler.handleEmptyError())) } - override fun onResume() { - super.onResume() - + override fun onStart() { + super.onStart() setupCheckout() activityCheckout?.destroyPurchaseFlow() @@ -135,6 +135,10 @@ class GiftIAPActivity: BaseActivity() { override fun onReady(billingRequests: BillingRequests, s: String, b: Boolean) {} }) + } + + override fun onResume() { + super.onResume() this.subscription1MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription1MonthNoRenew) }) this.subscription3MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription3MonthNoRenew) }) @@ -142,17 +146,23 @@ class GiftIAPActivity: BaseActivity() { this.subscription12MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription12MonthNoRenew) }) } - override fun onPause() { + override fun onStop() { activityCheckout?.stop() - super.onPause() + super.onStop() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) activityCheckout?.onActivityResult(requestCode, resultCode, data) - } + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + finish() + } + + return super.onOptionsItemSelected(item) + } private fun updateButtonLabel(sku: Sku, price: String, subscriptions: Inventory.Product) { val matchingView = buttonForSku(sku) @@ -197,9 +207,8 @@ class GiftIAPActivity: BaseActivity() { } private fun selectSubscription(sku: Sku) { - if (this.selectedSubscriptionSku != null) { - val oldButton = buttonForSku(this.selectedSubscriptionSku) - oldButton?.setIsPurchased(false) + for (thisSku in skus) { + buttonForSku(sku)?.setIsPurchased(false) } this.selectedSubscriptionSku = sku val subscriptionOptionButton = buttonForSku(this.selectedSubscriptionSku) @@ -229,4 +238,40 @@ class GiftIAPActivity: BaseActivity() { billingRequests?.purchase(ProductTypes.IN_APP, sku.id.code, null, it.purchaseFlow) } } + + + @Subscribe + public fun onConsumablePurchased(event: ConsumablePurchasedEvent) { + consumePurchase(event.purchase) + displayConfirmationDialog() + finish() + } + + private fun displayConfirmationDialog() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert) + } else { + AlertDialog.Builder(this) + } + .setTitle(R.string.gift_confirmation_title) + .setMessage(if (remoteConfigManager.enableGiftOneGetOne()) R.string.gift_confirmation_text_g1g1 else R.string.gift_confirmation_text) + .setPositiveButton(android.R.string.ok) { dialog, _ -> + dialog.dismiss() + } + .show() + } + + private fun consumePurchase(purchase: Purchase) { + if (PurchaseTypes.allGemTypes.contains(purchase.sku) || PurchaseTypes.allSubscriptionNoRenewTypes.contains(purchase.sku)) { + billingRequests?.consume(purchase.token, object : RequestListener { + + override fun onSuccess(result: Any) { + } + + override fun onError(response: Int, e: Exception) { + crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e) + } + }) + } + } } \ No newline at end of file