mirror of https://github.com/tasks/tasks
Convert Inventory to Kotlin
parent
5d771a2449
commit
f8d6914d37
@ -0,0 +1,70 @@
|
||||
package org.tasks.billing
|
||||
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import dagger.hilt.android.testing.UninstallModules
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.injection.InjectingTestCase
|
||||
import org.tasks.injection.ProductionModule
|
||||
import org.tasks.preferences.Preferences
|
||||
import javax.inject.Inject
|
||||
|
||||
@UninstallModules(ProductionModule::class)
|
||||
@HiltAndroidTest
|
||||
class InventoryTest : InjectingTestCase() {
|
||||
|
||||
@Inject lateinit var preferences: Preferences
|
||||
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
|
||||
@Inject lateinit var signatureVerifier: SignatureVerifier
|
||||
|
||||
lateinit var inventory: Inventory
|
||||
|
||||
@Test
|
||||
fun monthlyIsPro() {
|
||||
withPurchases(monthly01)
|
||||
|
||||
assertTrue(inventory.hasPro)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMonthlyUpgrade() {
|
||||
withPurchases(monthly01, monthly03)
|
||||
|
||||
assertEquals(3, inventory.subscription?.subscriptionPrice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMonthlyOverAnnual() {
|
||||
withPurchases(monthly01, annual03)
|
||||
|
||||
assertTrue(inventory.subscription!!.isMonthly)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isCancelled() {
|
||||
withPurchases(annual03Cancelled)
|
||||
|
||||
assertTrue(inventory.subscription!!.isCanceled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cancelledIsStillPro() {
|
||||
withPurchases(annual03Cancelled)
|
||||
|
||||
assertTrue(inventory.subscription!!.isProSubscription)
|
||||
}
|
||||
|
||||
private fun withPurchases(vararg purchases: String) {
|
||||
preferences.setPurchases(purchases.toHashSet())
|
||||
inventory = Inventory(preferences, signatureVerifier, localBroadcastManager)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val annual03 = "{\"mOriginalJson\":\"{\\\"orderId\\\":\\\"GPA.3372-3222-8630-38485\\\",\\\"packageName\\\":\\\"org.tasks\\\",\\\"productId\\\":\\\"annual_03\\\",\\\"purchaseTime\\\":1603917413542,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"ciogggalpbohflhmjamciehl.AO-J1OyjBpBOnwKCOBSN0Cil7yM65ZYnkn9nGqZO1n3nsHIF_LHv0ZuQqNnThB_JuCt-s9wBij1PyOCoP8axqVILXSiavcyPmg\\\",\\\"autoRenewing\\\":true}\",\"mParsedJson\":{\"nameValuePairs\":{\"orderId\":\"GPA.3372-3222-8630-38485\",\"packageName\":\"org.tasks\",\"productId\":\"annual_03\",\"purchaseTime\":1603917413542,\"purchaseState\":0,\"purchaseToken\":\"ciogggalpbohflhmjamciehl.AO-J1OyjBpBOnwKCOBSN0Cil7yM65ZYnkn9nGqZO1n3nsHIF_LHv0ZuQqNnThB_JuCt-s9wBij1PyOCoP8axqVILXSiavcyPmg\",\"autoRenewing\":true}},\"mSignature\":\"Od2ulMjFethYNdA1rTm7AvNMyfFgefCaZhtBeYuTHlMB/XbEd/m9noRlKWMnShFthnQyw97CfrB86aaB52OSWm9pGkPzaRtOJPyL8BJHP9LEjXHOQIQ2Nx9zRF30+EWgV4O0IyeL/o5eUvTQRNnfyUXFdJQRLiKTblQojO6mTCX2fA6lTAntjJpbTbYGuYZjg782gX5HvmwQN5CJu7ZVZCH9AmsnAqZgb7h+MXhquQjv0L4pDVDp3dyDDwgpCAvSRy3550ZANPfNGsQpPr9Iv9IGoK0/INZRrq63VEEAz2mBGkzJgyQUYVtT6AylvNrqdo0w17hs0MLfsj6dwvSlYw\\u003d\\u003d\"}"
|
||||
private const val monthly01 = "{\"mOriginalJson\":\"{\\\"orderId\\\":\\\"GPA.3369-0544-4429-52590\\\",\\\"packageName\\\":\\\"org.tasks\\\",\\\"productId\\\":\\\"monthly_01\\\",\\\"purchaseTime\\\":1603912474316,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"iibbhlkglfjcgdebphiklajb.AO-J1OyJd2kCytLMfT8Vszibf_E99ffLha5cHgOM8o3gYPKy1kD8nIZh0hcEEyOPe7fsdFJrR1-gtvg8WKLFNJoCdqrerJ2Z6Q\\\",\\\"autoRenewing\\\":true}\",\"mParsedJson\":{\"nameValuePairs\":{\"orderId\":\"GPA.3369-0544-4429-52590\",\"packageName\":\"org.tasks\",\"productId\":\"monthly_01\",\"purchaseTime\":1603912474316,\"purchaseState\":0,\"purchaseToken\":\"iibbhlkglfjcgdebphiklajb.AO-J1OyJd2kCytLMfT8Vszibf_E99ffLha5cHgOM8o3gYPKy1kD8nIZh0hcEEyOPe7fsdFJrR1-gtvg8WKLFNJoCdqrerJ2Z6Q\",\"autoRenewing\":true}},\"mSignature\":\"UK7fdCY61QownZW8jDLB1myUKf1llFh9rj5I7P8V03AgdA6LGpEUiCvMvCqHfMGpY3VewmawezqiCUdGWGr+UgS+6QHEuFjpO8L+E36JUDqlU9uoGrTsXLI1gXQNQElGJ71DrKlFBbyyBHSeGWnzijcq4DyyHQzpmsqijxfs0KGjkta2TiOCtyxS+YA569xaGi6lcLGTyMEe7wS5bcjdfwFir0uVtCP+iqjoEd3kt4/03l9BEJYgf8eBxI0vrm4O+jYDJu8gGMTSQZiSqb0wN4sq8D9ksV+BcI4az6LVa1d6nuD+ob0Woe0/P2uoXG8nTEZJnrAZjkG6q8736HP6rw\\u003d\\u003d\"}"
|
||||
private const val monthly03 = "{\"mOriginalJson\":\"{\\\"orderId\\\":\\\"GPA.3348-6247-8527-38213\\\",\\\"packageName\\\":\\\"org.tasks\\\",\\\"productId\\\":\\\"monthly_03\\\",\\\"purchaseTime\\\":1603912730414,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"cmomnojdllomadpoinoabbkd.AO-J1OypdY4iXbMrF21L6Evn3wZSccwiBq-d55G1BVcrkwuH69zOuqb35yZnVynEb9KEvnQvgYQsUpv1AD5749iU-eDo4TRV5A\\\",\\\"autoRenewing\\\":true}\",\"mParsedJson\":{\"nameValuePairs\":{\"orderId\":\"GPA.3348-6247-8527-38213\",\"packageName\":\"org.tasks\",\"productId\":\"monthly_03\",\"purchaseTime\":1603912730414,\"purchaseState\":0,\"purchaseToken\":\"cmomnojdllomadpoinoabbkd.AO-J1OypdY4iXbMrF21L6Evn3wZSccwiBq-d55G1BVcrkwuH69zOuqb35yZnVynEb9KEvnQvgYQsUpv1AD5749iU-eDo4TRV5A\",\"autoRenewing\":true}},\"mSignature\":\"FkkW5FPw2elWnenIoQT7U5BnL2prcuK0GJEaHKtObPujSGRfJWFfThe3yuQ0w9AuTO0EDbm7LbJI44AiVJmpva3Iz3U2np2eNBuUAJIw9eECvQjEvuYk6Vq7LIgJwEsTyA8xRwjLJm+R1mmMWOxURmvDVBgDTHCOJsdUI9s52CSTQf2Ek+XABHugrMJudO43LzDuV2sP9mCqXUnSLbBXe3zZKyhhuz7gD+/5yavkRsPOVcZnsJetdxEmnrip8JEvgtHAvciPkvSD/fYeXdAlY2HiQWK/S0/I+yRaCEK8V+Um78ibbYc4Ng5NcXDm44nTv3F6jQEzYy4qRv/ohmwEQg\\u003d\\u003d\"}"
|
||||
private const val annual03Cancelled = "{\"mOriginalJson\":\"{\\\"orderId\\\":\\\"GPA.3372-3222-8630-38485\\\",\\\"packageName\\\":\\\"org.tasks\\\",\\\"productId\\\":\\\"annual_03\\\",\\\"purchaseTime\\\":1603917413542,\\\"purchaseState\\\":0,\\\"purchaseToken\\\":\\\"ciogggalpbohflhmjamciehl.AO-J1OyjBpBOnwKCOBSN0Cil7yM65ZYnkn9nGqZO1n3nsHIF_LHv0ZuQqNnThB_JuCt-s9wBij1PyOCoP8axqVILXSiavcyPmg\\\",\\\"autoRenewing\\\":false}\",\"mParsedJson\":{\"nameValuePairs\":{\"orderId\":\"GPA.3372-3222-8630-38485\",\"packageName\":\"org.tasks\",\"productId\":\"annual_03\",\"purchaseTime\":1603917413542,\"purchaseState\":0,\"purchaseToken\":\"ciogggalpbohflhmjamciehl.AO-J1OyjBpBOnwKCOBSN0Cil7yM65ZYnkn9nGqZO1n3nsHIF_LHv0ZuQqNnThB_JuCt-s9wBij1PyOCoP8axqVILXSiavcyPmg\",\"autoRenewing\":false}},\"mSignature\":\"jL+2qRv0LtCutoJ86NWaInbx/9/kIWbxXRKYkou74TBjwu9KZ89EpJY632ImEy2xfLd8DHuVuWOcZY646I29Ny2E4HYNAsQEg2du4NRXEHZvu+py4Mi212KF8S2EPNdZCor1wiOJ0zRVBiRAtiCfqxHjQdfKn7FpDiHFrUhMu1huEAxJ0Xrnvxcmkouizw3wzKnAvI+O75LIWWZHCy+1o7s285cSKtQoztVY/nHInJLxV6dk93lAivOlEox+VCLU978lUvv45Rue50fMzS2CRsVFmRt9/yTP8RCiQKzGC/pyHtqNj/ceCrDi4VV8JPhsPd4NUaKk82Oq1xmGXtzEcQ\\u003d\\u003d\"}"
|
||||
}
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
package org.tasks.billing;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.tasks.BuildConfig;
|
||||
import org.tasks.LocalBroadcastManager;
|
||||
import org.tasks.R;
|
||||
import org.tasks.preferences.Preferences;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Singleton
|
||||
public class Inventory {
|
||||
|
||||
private static final String SKU_VIP = "vip";
|
||||
public static final String SKU_TASKER = "tasker";
|
||||
public static final String SKU_THEMES = "themes";
|
||||
|
||||
private final Preferences preferences;
|
||||
private final SignatureVerifier signatureVerifier;
|
||||
private final LocalBroadcastManager localBroadcastManager;
|
||||
|
||||
private final Map<String, Purchase> purchases = new HashMap<>();
|
||||
private Purchase subscription = null;
|
||||
|
||||
@Inject
|
||||
public Inventory(
|
||||
Preferences preferences,
|
||||
SignatureVerifier signatureVerifier,
|
||||
LocalBroadcastManager localBroadcastManager) {
|
||||
this.preferences = preferences;
|
||||
this.signatureVerifier = signatureVerifier;
|
||||
this.localBroadcastManager = localBroadcastManager;
|
||||
for (Purchase purchase : preferences.getPurchases()) {
|
||||
verifyAndAdd(purchase);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Timber.d("clear()");
|
||||
purchases.clear();
|
||||
}
|
||||
|
||||
public void add(Iterable<Purchase> purchases) {
|
||||
for (Purchase purchase : purchases) {
|
||||
verifyAndAdd(purchase);
|
||||
}
|
||||
preferences.setPurchases(this.purchases.values());
|
||||
localBroadcastManager.broadcastPurchasesUpdated();
|
||||
}
|
||||
|
||||
private void verifyAndAdd(Purchase purchase) {
|
||||
if (signatureVerifier.verifySignature(purchase)) {
|
||||
Timber.d("add(%s)", purchase);
|
||||
purchases.put(purchase.getSku(), purchase);
|
||||
if (purchase.isProSubscription() && (subscription == null || subscription.isCanceled())) {
|
||||
subscription = purchase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean purchasedTasker() {
|
||||
return hasPro() || purchases.containsKey(SKU_TASKER);
|
||||
}
|
||||
|
||||
public boolean purchasedThemes() {
|
||||
return hasPro() || purchases.containsKey(SKU_THEMES);
|
||||
}
|
||||
|
||||
public Purchase getSubscription() {
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public boolean hasPro() {
|
||||
//noinspection ConstantConditions
|
||||
return subscription != null
|
||||
|| purchases.containsKey(SKU_VIP)
|
||||
|| BuildConfig.FLAVOR.equals("generic")
|
||||
|| (BuildConfig.DEBUG && preferences.getBoolean(R.string.p_debug_pro, false));
|
||||
}
|
||||
|
||||
boolean purchased(String sku) {
|
||||
return purchases.containsKey(sku);
|
||||
}
|
||||
|
||||
public Purchase getPurchase(String sku) {
|
||||
return purchases.get(sku);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package org.tasks.billing
|
||||
|
||||
import org.tasks.BuildConfig
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.R
|
||||
import org.tasks.preferences.Preferences
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class Inventory @Inject constructor(
|
||||
private val preferences: Preferences,
|
||||
private val signatureVerifier: SignatureVerifier,
|
||||
private val localBroadcastManager: LocalBroadcastManager
|
||||
) {
|
||||
private val purchases: MutableMap<String, Purchase> = HashMap()
|
||||
|
||||
fun clear() {
|
||||
Timber.d("clear()")
|
||||
purchases.clear()
|
||||
}
|
||||
|
||||
fun add(purchases: Iterable<Purchase>) {
|
||||
verifyAndAdd(purchases)
|
||||
preferences.setPurchases(this.purchases.values)
|
||||
localBroadcastManager.broadcastPurchasesUpdated()
|
||||
}
|
||||
|
||||
private fun verifyAndAdd(items: Iterable<Purchase>) {
|
||||
for (purchase in items) {
|
||||
if (signatureVerifier.verifySignature(purchase)) {
|
||||
Timber.d("add(%s)", purchase)
|
||||
this.purchases[purchase.sku] = purchase
|
||||
}
|
||||
}
|
||||
hasPro = purchases.values.any { it.isProSubscription } || purchases.containsKey(SKU_VIP)
|
||||
}
|
||||
|
||||
fun purchasedTasker() = hasPro || purchases.containsKey(SKU_TASKER)
|
||||
|
||||
fun purchasedThemes() = hasPro || purchases.containsKey(SKU_THEMES)
|
||||
|
||||
var hasPro = false
|
||||
get() {
|
||||
return BuildConfig.FLAVOR == "generic"
|
||||
|| (BuildConfig.DEBUG && preferences.getBoolean(R.string.p_debug_pro, false))
|
||||
|| field
|
||||
}
|
||||
private set
|
||||
|
||||
fun purchased(sku: String) = purchases.containsKey(sku)
|
||||
|
||||
fun getPurchase(sku: String) = purchases[sku]
|
||||
|
||||
val subscription: Purchase?
|
||||
get() = purchases
|
||||
.values
|
||||
.filter { it.isProSubscription }
|
||||
.sortedWith{ l, r ->
|
||||
r.isMonthly.compareTo(l.isMonthly)
|
||||
.takeIf { it != 0 }?.let { return@sortedWith it }
|
||||
l.isCanceled.compareTo(r.isCanceled)
|
||||
.takeIf { it != 0 }?.let { return@sortedWith it }
|
||||
return@sortedWith r.subscriptionPrice!!.compareTo(l.subscriptionPrice!!)
|
||||
}
|
||||
.firstOrNull()
|
||||
|
||||
companion object {
|
||||
private const val SKU_VIP = "vip"
|
||||
const val SKU_TASKER = "tasker"
|
||||
const val SKU_THEMES = "themes"
|
||||
}
|
||||
|
||||
init {
|
||||
verifyAndAdd(preferences.purchases)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue