diff --git a/Habitica/res/layout/dialog_insufficient_gems.xml b/Habitica/res/layout/dialog_insufficient_gems.xml
index 048b23d47..5d9029955 100644
--- a/Habitica/res/layout/dialog_insufficient_gems.xml
+++ b/Habitica/res/layout/dialog_insufficient_gems.xml
@@ -1,9 +1,10 @@
-
+ android:gravity="center_horizontal" />
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 0a61a354d..e47ec5502 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -847,4 +847,5 @@
Party Activity
Need Gems?
Become a Subscriber to buy Gems with gold, get monthly mystery items, increased drop caps and more!
+ See other Options
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java
index 051065f41..ab5e56840 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java
@@ -94,6 +94,7 @@ import com.habitrpg.android.habitica.ui.fragments.tasks.TasksFragment;
import com.habitrpg.android.habitica.ui.viewmodels.GroupViewModel;
import com.habitrpg.android.habitica.ui.viewmodels.InboxViewModel;
import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel;
+import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientGemsDialog;
import com.habitrpg.android.habitica.ui.views.shops.PurchaseDialog;
import com.habitrpg.android.habitica.ui.views.social.ChatBarView;
import com.habitrpg.android.habitica.ui.views.stats.BulkAllocateStatsDialog;
@@ -316,4 +317,6 @@ public interface UserComponent {
void inject(@NotNull AchievementsFragment achievementsFragment);
void inject(@NotNull InboxViewModel inboxViewModel);
+
+ void inject(@NotNull InsufficientGemsDialog insufficientGemsDialog);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt
new file mode 100644
index 000000000..fec1c9133
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt
@@ -0,0 +1,207 @@
+package com.habitrpg.android.habitica.helpers
+
+import android.app.Activity
+import android.content.Intent
+import com.habitrpg.android.habitica.HabiticaBaseApplication
+import com.habitrpg.android.habitica.HabiticaPurchaseVerifier
+import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
+import org.solovyev.android.checkout.*
+import java.util.*
+
+class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy) {
+ private val billing = HabiticaBaseApplication.getInstance(activity.applicationContext)?.billing
+ private val checkout = billing?.let { Checkout.forActivity(activity, it) }
+ private val inventory = checkout?.makeInventory()
+
+ private var billingRequests: BillingRequests? = null
+ private var isStarted = false
+
+ var whenCheckoutReady: (() -> Unit)? = null
+
+ init {
+ handlers[activity] = this
+ }
+
+ fun startListening() {
+ if (!isStarted) {
+ checkout?.start()
+ isStarted = true
+
+ checkout?.whenReady(object : Checkout.Listener {
+ override fun onReady(requests: BillingRequests) {
+ this@PurchaseHandler.billingRequests = requests
+ checkIfPendingPurchases()
+ whenCheckoutReady?.invoke()
+ }
+
+ override fun onReady(requests: BillingRequests, product: String, billingSupported: Boolean) {}
+ })
+ }
+ }
+
+ fun stopListening() {
+ if (isStarted) {
+ checkout?.stop()
+ isStarted = false
+ }
+ }
+
+ fun onResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ checkout?.onActivityResult(requestCode, resultCode, data)
+ }
+
+ fun getAllGemSKUs(onSuccess: ((List) -> Unit)) {
+ getSKUs(ProductTypes.IN_APP, PurchaseTypes.allGemTypes, onSuccess)
+ }
+
+ fun getAllSubscriptionSKUs(onSuccess: ((List) -> Unit)) {
+ getSKUs(ProductTypes.SUBSCRIPTION, PurchaseTypes.allSubscriptionTypes, onSuccess)
+ }
+
+ fun getAllSubscriptionProducts(onSuccess: ((Inventory.Product) -> Unit)) {
+ getProduct(ProductTypes.SUBSCRIPTION, PurchaseTypes.allSubscriptionTypes, onSuccess)
+ }
+
+ fun getAllGiftSubscriptionSKUs(onSuccess: ((List) -> Unit)) {
+ getSKUs(ProductTypes.IN_APP, PurchaseTypes.allSubscriptionNoRenewTypes, onSuccess)
+ }
+
+ fun getInAppPurchaseSKU(identifier: String, onSuccess: ((Sku) -> Unit)) {
+ getSKU(ProductTypes.IN_APP, identifier, onSuccess)
+ }
+
+ fun getSubscriptionSKU(identifier: String, onSuccess: ((Sku) -> Unit)) {
+ getSKU(ProductTypes.SUBSCRIPTION, identifier, onSuccess)
+ }
+
+
+ private fun getSKUs(type: String, identifiers: List, onSuccess: ((List) -> Unit)) {
+ getProduct(type, identifiers) {
+ onSuccess(it.skus)
+ }
+ }
+
+ private fun getProduct(type: String, identifiers: List, onSuccess: ((Inventory.Product) -> Unit)) {
+ inventory?.load(Inventory.Request.create()
+ .loadAllPurchases().loadSkus(type, identifiers)) { products ->
+ val purchases = products.get(type)
+ if (!purchases.supported) return@load
+ onSuccess(purchases)
+ }
+ }
+
+ private fun getSKU(type: String, identifier: String, onSuccess: ((Sku) -> Unit)) {
+ inventory?.load(Inventory.Request.create()
+ .loadAllPurchases().loadSkus(type, listOf(identifier))) { products ->
+ val purchases = products.get(type)
+ if (!purchases.supported) return@load
+ purchases.skus.firstOrNull()?.let { onSuccess(it) }
+ }
+ }
+
+ fun purchaseSubscription(sku: Sku) {
+ sku.id.code?.let { code ->
+ billingRequests?.isPurchased(ProductTypes.SUBSCRIPTION, code, object : RequestListener {
+ override fun onSuccess(aBoolean: Boolean) {
+ if (!aBoolean) {
+ // no current product exist
+ checkout?.let {
+ billingRequests?.purchase(ProductTypes.SUBSCRIPTION, code, null, it.purchaseFlow)
+ }
+ }
+ }
+
+ override fun onError(i: Int, e: Exception) {}
+ })
+ }
+ }
+
+ private fun checkIfPendingPurchases() {
+ billingRequests?.getAllPurchases(ProductTypes.IN_APP, object : RequestListener {
+ override fun onSuccess(purchases: Purchases) {
+ for (purchase in purchases.list) {
+ if (PurchaseTypes.allGemTypes.contains(purchase.sku)) {
+ billingRequests?.consume(purchase.token, object : RequestListener {
+ override fun onSuccess(o: Any) {
+ //EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD));
+ }
+
+ override fun onError(i: Int, e: Exception) {
+ crashlyticsProxy.fabricLogE("Purchase", "Consume", e)
+ }
+ })
+ }
+ }
+ }
+
+ override fun onError(i: Int, e: Exception) {
+ crashlyticsProxy.fabricLogE("Purchase", "getAllPurchases", e)
+ }
+ })
+ }
+
+ fun purchaseGems(identifier: String) {
+ checkout?.let {
+ it.destroyPurchaseFlow()
+ billingRequests?.purchase(ProductTypes.IN_APP, identifier, null, it.createOneShotPurchaseFlow(object : RequestListener {
+ override fun onSuccess(result: Purchase) {
+ billingRequests?.consume(result.token, object : RequestListener {
+ override fun onSuccess(o: Any) {
+ }
+
+ override fun onError(i: Int, e: Exception) {
+ crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
+ }
+ })
+ }
+
+ override fun onError(response: Int, e: java.lang.Exception) {
+ e.printStackTrace()
+ }
+ }))
+ }
+ }
+
+ fun purchaseGiftedSubscription(sku: Sku, giftedUserID: String?) {
+ checkout?.let {
+ HabiticaPurchaseVerifier.pendingGifts[sku.id.code] = giftedUserID
+ billingRequests?.purchase(ProductTypes.IN_APP, sku.id.code, null, it.createOneShotPurchaseFlow(object : RequestListener {
+ override fun onSuccess(result: Purchase) {
+ billingRequests?.consume(result.token, object : RequestListener {
+ override fun onSuccess(o: Any) {
+ }
+
+ override fun onError(i: Int, e: Exception) {
+ crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
+ }
+ })
+ }
+
+ override fun onError(response: Int, e: java.lang.Exception) {
+
+ }
+ }))
+ }
+ }
+
+ 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)
+ }
+ })
+ }
+ }
+
+ companion object {
+
+ private var handlers = WeakHashMap()
+
+ fun findForActivity(activity: Activity): PurchaseHandler? {
+ return handlers[activity]
+ }
+ }
+}
\ No newline at end of file
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 909ac99fb..ea1304d21 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
@@ -3,21 +3,18 @@ package com.habitrpg.android.habitica.ui.activities
import android.content.Intent
import android.os.Bundle
-import android.util.Log
import android.view.MenuItem
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
-import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent
-import com.habitrpg.android.habitica.helpers.PurchaseTypes
+import com.habitrpg.android.habitica.helpers.PurchaseHandler
import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
import com.habitrpg.android.habitica.ui.fragments.GemsPurchaseFragment
import com.habitrpg.android.habitica.ui.fragments.SubscriptionFragment
import org.greenrobot.eventbus.Subscribe
-import org.solovyev.android.checkout.*
import javax.inject.Inject
class GemPurchaseActivity : BaseActivity() {
@@ -29,9 +26,7 @@ class GemPurchaseActivity : BaseActivity() {
internal var fragment: CheckoutFragment? = null
var isActive = false
- var activityCheckout: ActivityCheckout? = null
- private set
- private var billingRequests: BillingRequests? = null
+ var purchaseHandler: PurchaseHandler? = null
override fun getLayoutResId(): Int {
return R.layout.activity_gem_purchase
@@ -43,7 +38,7 @@ class GemPurchaseActivity : BaseActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- activityCheckout?.onActivityResult(requestCode, resultCode, data)
+ purchaseHandler?.onResult(requestCode, resultCode, data)
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -56,6 +51,8 @@ class GemPurchaseActivity : BaseActivity() {
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setTitle(R.string.gem_purchase_toolbartitle)
+ purchaseHandler = PurchaseHandler(this, crashlyticsProxy)
+
if (intent.extras?.containsKey("openSubscription") == true) {
if (intent.extras?.getBoolean("openSubscription") == false) {
createFragment(false)
@@ -65,40 +62,15 @@ class GemPurchaseActivity : BaseActivity() {
} else {
createFragment(true)
}
+
+ purchaseHandler?.whenCheckoutReady = {
+ fragment?.setupCheckout()
+ }
}
override fun onStart() {
super.onStart()
- setupCheckout()
-
- activityCheckout?.destroyPurchaseFlow()
-
- activityCheckout?.createPurchaseFlow(object : RequestListener {
- override fun onSuccess(purchase: Purchase) {
-
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseFlowException", "Error", e)
- val billingError = e as? BillingException
- if (billingError != null) {
- Log.e("BILLING ERROR", billingError.toString())
- }
- }
- })
-
-
- activityCheckout?.whenReady(object : Checkout.Listener {
- override fun onReady(billingRequests: BillingRequests) {
- this@GemPurchaseActivity.billingRequests = billingRequests
-
- fragment?.setBillingRequests(billingRequests)
-
- checkIfPendingPurchases()
- }
-
- override fun onReady(billingRequests: BillingRequests, s: String, b: Boolean) {}
- })
+ purchaseHandler?.startListening()
}
override fun onResume() {
@@ -112,7 +84,7 @@ class GemPurchaseActivity : BaseActivity() {
}
public override fun onStop() {
- activityCheckout?.stop()
+ purchaseHandler?.stopListening()
super.onStop()
}
@@ -124,25 +96,13 @@ class GemPurchaseActivity : BaseActivity() {
return super.onOptionsItemSelected(item)
}
- private fun setupCheckout() {
- HabiticaBaseApplication.getInstance(this)?.billing?.let {
- activityCheckout = Checkout.forActivity(this, it)
- activityCheckout?.start()
- }
-
- }
-
private fun createFragment(showSubscription: Boolean) {
val fragment: CheckoutFragment = if (showSubscription) {
SubscriptionFragment()
} else {
GemsPurchaseFragment()
}
- fragment.setListener(this@GemPurchaseActivity)
- fragment.setupCheckout()
- if (billingRequests != null) {
- fragment.setBillingRequests(billingRequests)
- }
+ fragment.setPurchaseHandler(purchaseHandler)
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment as Fragment)
@@ -150,58 +110,15 @@ class GemPurchaseActivity : BaseActivity() {
this.fragment = fragment
}
- private fun checkIfPendingPurchases() {
- billingRequests?.getAllPurchases(ProductTypes.IN_APP, object : RequestListener {
- override fun onSuccess(purchases: Purchases) {
- for (purchase in purchases.list) {
- if (PurchaseTypes.allGemTypes.contains(purchase.sku)) {
- billingRequests?.consume(purchase.token, object : RequestListener {
- override fun onSuccess(o: Any) {
- //EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD));
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("Purchase", "Consume", e)
- }
- })
- }
- }
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("Purchase", "getAllPurchases", e)
- }
- })
- }
-
@Subscribe
fun onConsumablePurchased(event: ConsumablePurchasedEvent) {
if (isActive) {
- consumePurchase(event.purchase)
+ purchaseHandler?.consumePurchase(event.purchase)
}
}
interface CheckoutFragment {
-
fun setupCheckout()
-
- fun setListener(listener: GemPurchaseActivity)
-
- 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)
- }
- })
- }
+ fun setPurchaseHandler(handler: PurchaseHandler?)
}
}
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 17a641765..38576bc15 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
@@ -9,14 +9,13 @@ import android.widget.Button
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.core.view.isVisible
-import com.habitrpg.android.habitica.HabiticaBaseApplication
-import com.habitrpg.android.habitica.HabiticaPurchaseVerifier
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent
import com.habitrpg.android.habitica.extensions.addOkButton
import com.habitrpg.android.habitica.helpers.AppConfigManager
+import com.habitrpg.android.habitica.helpers.PurchaseHandler
import com.habitrpg.android.habitica.helpers.PurchaseTypes
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
@@ -28,7 +27,8 @@ 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 org.solovyev.android.checkout.Inventory
+import org.solovyev.android.checkout.Sku
import javax.inject.Inject
@@ -41,9 +41,7 @@ class GiftIAPActivity: BaseActivity() {
@Inject
lateinit var appConfigManager: AppConfigManager
- var activityCheckout: ActivityCheckout? = null
- private set
- private var billingRequests: BillingRequests? = null
+ private var purchaseHandler: PurchaseHandler? = null
private val toolbar: Toolbar by bindView(R.id.toolbar)
@@ -102,38 +100,8 @@ class GiftIAPActivity: BaseActivity() {
override fun onStart() {
super.onStart()
- setupCheckout()
-
- activityCheckout?.destroyPurchaseFlow()
-
- activityCheckout?.createPurchaseFlow(object : RequestListener {
- override fun onSuccess(purchase: Purchase) {
- if (PurchaseTypes.allSubscriptionNoRenewTypes.contains(purchase.sku)) {
- billingRequests?.consume(purchase.token, object : RequestListener {
- override fun onSuccess(o: Any) {
- finish()
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
- }
- })
- }
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseFlowException", "Error", e)
- }
- })
-
-
- activityCheckout?.whenReady(object : Checkout.Listener {
- override fun onReady(billingRequests: BillingRequests) {
- this@GiftIAPActivity.billingRequests = billingRequests
- }
-
- override fun onReady(billingRequests: BillingRequests, s: String, b: Boolean) {}
- })
+ purchaseHandler = PurchaseHandler(this, crashlyticsProxy)
+ purchaseHandler?.startListening()
}
override fun onResume() {
@@ -146,13 +114,13 @@ class GiftIAPActivity: BaseActivity() {
}
override fun onStop() {
- activityCheckout?.stop()
+ purchaseHandler?.stopListening()
super.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- activityCheckout?.onActivityResult(requestCode, resultCode, data)
+ purchaseHandler?.onResult(requestCode, resultCode, data)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -172,30 +140,6 @@ class GiftIAPActivity: BaseActivity() {
}
}
- private fun setupCheckout() {
- HabiticaBaseApplication.getInstance(this)?.billing?.let {
- activityCheckout = Checkout.forActivity(this, it)
- activityCheckout?.start()
- }
- val checkout = activityCheckout
- if (checkout != null) {
- val inventory = checkout.makeInventory()
-
- inventory.load(Inventory.Request.create()
- .loadAllPurchases().loadSkus(ProductTypes.IN_APP, PurchaseTypes.allSubscriptionNoRenewTypes)
- ) { products ->
- val subscriptions = products.get(ProductTypes.IN_APP)
-
- skus = subscriptions.skus
-
- for (sku in skus) {
- updateButtonLabel(sku, sku.price, subscriptions)
- }
- selectSubscription(PurchaseTypes.Subscription1MonthNoRenew)
- }
- }
- }
-
private fun selectSubscription(sku: String) {
for (thisSku in skus) {
if (thisSku.id.code == sku) {
@@ -235,16 +179,13 @@ class GiftIAPActivity: BaseActivity() {
if (giftedUserID?.isNotEmpty() != true) {
return
}
- activityCheckout?.let {
- HabiticaPurchaseVerifier.pendingGifts[sku.id.code] = giftedUserID
- billingRequests?.purchase(ProductTypes.IN_APP, sku.id.code, null, it.purchaseFlow)
- }
+ purchaseHandler?.purchaseGiftedSubscription(sku, giftedUserID)
}
@Subscribe
fun onConsumablePurchased(event: ConsumablePurchasedEvent) {
- consumePurchase(event.purchase)
+ purchaseHandler?.consumePurchase(event.purchase)
runOnUiThread {
displayConfirmationDialog()
}
@@ -275,18 +216,4 @@ class GiftIAPActivity: BaseActivity() {
}
alert.enqueue()
}
-
- 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
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
index 3f0746e3c..35173d481 100755
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
@@ -406,6 +406,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
data.getStringExtra("notificationId")
)
}
+ PurchaseHandler.findForActivity(this)?.onResult(requestCode, resultCode, data)
}
// region Events
@@ -740,6 +741,11 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
}.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
}
+ @Subscribe
+ fun onConsumablePurchased(event: ConsumablePurchasedEvent) {
+ userRepository.retrieveUser(false, true).subscribe(Consumer {}, RxErrorHandler.handleEmptyError())
+ }
+
companion object {
const val SELECT_CLASS_RESULT = 11
const val GEM_PURCHASE_REQUEST = 111
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt
index 21b771b9b..539cb5335 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/NavigationDrawerAdapter.kt
@@ -55,7 +55,7 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int): Recycle
items.indexOfFirst { it.identifier == identifier }
fun updateItem(item: HabiticaDrawerItem) {
- val position = getItemPosition(item.transitionId)
+ val position = getItemPosition(item.identifier)
items[position] = item
notifyDataSetChanged()
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt
index b4e7d379f..afba8f607 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/GemsPurchaseFragment.kt
@@ -10,6 +10,7 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.extensions.inflate
+import com.habitrpg.android.habitica.helpers.PurchaseHandler
import com.habitrpg.android.habitica.helpers.PurchaseTypes
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
@@ -19,9 +20,6 @@ import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.android.habitica.ui.views.promo.SubscriptionBuyGemsPromoView
import io.reactivex.functions.Consumer
-import org.solovyev.android.checkout.BillingRequests
-import org.solovyev.android.checkout.Inventory
-import org.solovyev.android.checkout.ProductTypes
import javax.inject.Inject
class GemsPurchaseFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragment {
@@ -38,8 +36,7 @@ class GemsPurchaseFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
@Inject
lateinit var userRepository: UserRepository
- private var listener: GemPurchaseActivity? = null
- private var billingRequests: BillingRequests? = null
+ private var purchaseHandler: PurchaseHandler? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
@@ -70,32 +67,15 @@ class GemsPurchaseFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
}
override fun setupCheckout() {
- val checkout = listener?.activityCheckout
- if (checkout != null) {
- val inventory = checkout.makeInventory()
-
- inventory.load(Inventory.Request.create()
- .loadAllPurchases().loadSkus(ProductTypes.IN_APP, PurchaseTypes.allGemTypes)
- ) { products ->
- val gems = products.get(ProductTypes.IN_APP)
- if (!gems.supported) {
- // billing is not supported, user can't purchase anything
- return@load
- }
- val skus = gems.skus
- for (sku in skus) {
- updateButtonLabel(sku.id.code, sku.price)
- }
+ purchaseHandler?.getAllGemSKUs { skus ->
+ for (sku in skus) {
+ updateButtonLabel(sku.id.code, sku.price)
}
}
}
- override fun setListener(listener: GemPurchaseActivity) {
- this.listener = listener
- }
-
- override fun setBillingRequests(billingRequests: BillingRequests?) {
- this.billingRequests = billingRequests
+ override fun setPurchaseHandler(handler: PurchaseHandler?) {
+ this.purchaseHandler = handler
}
private fun updateButtonLabel(sku: String, price: String) {
@@ -112,9 +92,7 @@ class GemsPurchaseFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
}
}
- fun purchaseGems(sku: String) {
- listener?.activityCheckout?.let {
- billingRequests?.purchase(ProductTypes.IN_APP, sku, null, it.purchaseFlow)
- }
+ fun purchaseGems(identifier: String) {
+ purchaseHandler?.purchaseGems(identifier)
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt
index 4d1fb4a36..02e4a70fc 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt
@@ -14,6 +14,7 @@ import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.events.UserSubscribedEvent
import com.habitrpg.android.habitica.extensions.addCancelButton
import com.habitrpg.android.habitica.helpers.AppConfigManager
+import com.habitrpg.android.habitica.helpers.PurchaseHandler
import com.habitrpg.android.habitica.helpers.PurchaseTypes
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.user.User
@@ -30,7 +31,8 @@ import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionVi
import io.reactivex.functions.Consumer
import kotlinx.android.synthetic.main.fragment_subscription.*
import org.greenrobot.eventbus.Subscribe
-import org.solovyev.android.checkout.*
+import org.solovyev.android.checkout.Inventory
+import org.solovyev.android.checkout.Sku
import javax.inject.Inject
class SubscriptionFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragment {
@@ -77,8 +79,7 @@ class SubscriptionFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
private var selectedSubscriptionSku: Sku? = null
private var skus: List = emptyList()
- private var listener: GemPurchaseActivity? = null
- private var billingRequests: BillingRequests? = null
+ private var purchaseHandler: PurchaseHandler? = null
private var user: User? = null
private var hasLoadedSubscriptionOptions: Boolean = false
@@ -140,24 +141,13 @@ class SubscriptionFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
}
override fun setupCheckout() {
- val checkout = listener?.activityCheckout
- if (checkout != null) {
- val inventory = checkout.makeInventory()
-
- inventory.load(Inventory.Request.create()
- .loadAllPurchases().loadSkus(ProductTypes.SUBSCRIPTION, PurchaseTypes.allSubscriptionTypes)
- ) { products ->
- val subscriptions = products.get(ProductTypes.SUBSCRIPTION)
-
- skus = subscriptions.skus
-
- for (sku in skus) {
- updateButtonLabel(sku, sku.price, subscriptions)
- }
- selectSubscription(PurchaseTypes.Subscription1Month)
- hasLoadedSubscriptionOptions = true
- updateSubscriptionInfo()
+ purchaseHandler?.getAllSubscriptionProducts {subscriptions ->
+ for (sku in skus) {
+ updateButtonLabel(sku, sku.price, subscriptions)
}
+ selectSubscription(PurchaseTypes.Subscription1Month)
+ hasLoadedSubscriptionOptions = true
+ updateSubscriptionInfo()
}
}
@@ -206,31 +196,13 @@ class SubscriptionFragment : BaseFragment(), GemPurchaseActivity.CheckoutFragmen
}
}
- override fun setListener(listener: GemPurchaseActivity) {
- this.listener = listener
- }
-
- override fun setBillingRequests(billingRequests: BillingRequests?) {
- this.billingRequests = billingRequests
+ override fun setPurchaseHandler(handler: PurchaseHandler?) {
+ this.purchaseHandler = handler
}
private fun purchaseSubscription() {
- selectedSubscriptionSku?.id?.code?.let { code ->
- billingRequests?.isPurchased(ProductTypes.SUBSCRIPTION, code, object : RequestListener {
- override fun onSuccess(aBoolean: Boolean) {
- if (!aBoolean) {
- // no current product exist
- val checkout = listener?.activityCheckout
- checkout?.let {
- billingRequests?.purchase(ProductTypes.SUBSCRIPTION, code, null, it.purchaseFlow)
- }
- }
- }
-
- override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("Purchase", "Error", e)
- }
- })
+ selectedSubscriptionSku?.let { sku ->
+ purchaseHandler?.purchaseSubscription(sku)
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt
index d1086dc49..02a497384 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt
@@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui.views.dialogs
import android.app.Activity
import android.content.Context
+import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -208,6 +209,14 @@ open class HabiticaAlertDialog(context: Context) : AlertDialog(context, R.style.
super.dismiss()
}
+ fun getActivity(): Activity? {
+ var thisContext = context
+ while (thisContext as? ContextThemeWrapper != null && thisContext as? Activity == null) {
+ thisContext = thisContext.baseContext
+ }
+ return thisContext as? Activity
+ }
+
companion object {
private var dialogQueue = mutableListOf()
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt
index f6b45d157..44f5cac4c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt
@@ -16,11 +16,13 @@ abstract class InsufficientCurrencyDialog(context: Context) : HabiticaAlertDialo
protected var imageView: ImageView
protected var textView: TextView
- open var layoutID = R.layout.dialog_insufficient_currency
+ open fun getLayoutID(): Int {
+ return R.layout.dialog_insufficient_currency
+ }
init {
val inflater = LayoutInflater.from(context)
- val view = inflater.inflate(layoutID, contentView, false)
+ val view = inflater.inflate(getLayoutID(), contentView, false)
setAdditionalContentView(view)
imageView = view.findViewById(R.id.imageView)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt
index eb96fc334..3f3b07a75 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientGemsDialog.kt
@@ -1,10 +1,23 @@
package com.habitrpg.android.habitica.ui.views.insufficientCurrency
import android.content.Context
+import android.view.View
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.core.os.bundleOf
+import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent
import com.habitrpg.android.habitica.extensions.addCloseButton
+import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
+import com.habitrpg.android.habitica.helpers.PurchaseHandler
+import com.habitrpg.android.habitica.helpers.PurchaseTypes
+import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import javax.inject.Inject
/**
* Created by phillip on 27.09.17.
@@ -12,13 +25,64 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController
class InsufficientGemsDialog(context: Context) : InsufficientCurrencyDialog(context) {
- override var layoutID: Int = R.layout.dialog_insufficient_gems
+ private var purchaseButton: Button? = null
+ @Inject
+ lateinit var configManager: AppConfigManager
+ @Inject
+ lateinit var crashlyticsProxy: CrashlyticsProxy
+
+ private var purchaseHandler: PurchaseHandler? = null
+
+ override fun getLayoutID(): Int {
+ return R.layout.dialog_insufficient_gems
+ }
init {
+ HabiticaBaseApplication.userComponent?.inject(this)
imageView.setImageResource(R.drawable.gems_84)
textView.setText(R.string.insufficientGems)
- addButton(R.string.purchase_gems, true) { _, _ -> MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", true))) }
+
+ addButton(R.string.see_other_options, false) { _, _ -> MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", false))) }
addCloseButton()
+ if (!configManager.insufficientGemPurchase()) {
+ contentView.findViewWithTag(R.id.purchase_wrapper).visibility = View.GONE
+ }
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ if (configManager.insufficientGemPurchase()) {
+ getActivity()?.let {
+ purchaseButton = contentView.findViewById(R.id.purchase_button)
+ purchaseHandler = PurchaseHandler(it, crashlyticsProxy)
+ purchaseHandler?.startListening()
+ purchaseHandler?.whenCheckoutReady = {
+ purchaseHandler?.getInAppPurchaseSKU(PurchaseTypes.Purchase4Gems) {sku ->
+ val purchaseTextView = contentView.findViewById(R.id.purchase_textview)
+ purchaseTextView.text = sku.displayTitle
+ purchaseButton?.text = sku.price
+ }
+ }
+
+ purchaseButton?.setOnClickListener {
+ purchaseHandler?.purchaseGems(PurchaseTypes.Purchase4Gems)
+ }
+ }
+ }
+ EventBus.getDefault().register(this)
+ }
+
+ override fun onDetachedFromWindow() {
+ if (EventBus.getDefault().isRegistered(this)) {
+ EventBus.getDefault().unregister(this)
+ }
+ super.onDetachedFromWindow()
+ }
+
+ @Subscribe
+ fun onConsumablePurchased(event: ConsumablePurchasedEvent) {
+ purchaseHandler?.consumePurchase(event.purchase)
+ dismiss()
}
}