diff --git a/app/src/androidTest/java/org/tasks/billing/InventoryTest.kt b/app/src/androidTest/java/org/tasks/billing/InventoryTest.kt new file mode 100644 index 000000000..c739d63d4 --- /dev/null +++ b/app/src/androidTest/java/org/tasks/billing/InventoryTest.kt @@ -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\"}" + } +} \ No newline at end of file diff --git a/app/src/googleplay/java/org/tasks/billing/SignatureVerifier.kt b/app/src/googleplay/java/org/tasks/billing/SignatureVerifier.kt index 98582cf40..c5ecf2ac4 100644 --- a/app/src/googleplay/java/org/tasks/billing/SignatureVerifier.kt +++ b/app/src/googleplay/java/org/tasks/billing/SignatureVerifier.kt @@ -7,7 +7,7 @@ import timber.log.Timber import java.io.IOException import javax.inject.Inject -internal class SignatureVerifier @Inject constructor(@ApplicationContext context: Context) { +class SignatureVerifier @Inject constructor(@ApplicationContext context: Context) { private val billingKey: String = context.getString(R.string.gp_key) fun verifySignature(purchase: Purchase): Boolean { diff --git a/app/src/googleplay/java/org/tasks/injection/LocationModule.kt b/app/src/googleplay/java/org/tasks/injection/LocationModule.kt index dc7322dc6..559306123 100644 --- a/app/src/googleplay/java/org/tasks/injection/LocationModule.kt +++ b/app/src/googleplay/java/org/tasks/injection/LocationModule.kt @@ -24,7 +24,7 @@ internal class LocationModule { inventory: Inventory): PlaceSearchProvider { return if (preferences.useGooglePlaces() && playServices.isPlayServicesAvailable - && inventory.hasPro()) { + && inventory.hasPro) { GooglePlacesSearchProvider(context) } else { MapboxSearchProvider(context) diff --git a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt index f4b4c842c..e0018be9a 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt @@ -86,7 +86,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl super.onCreate(savedInstanceState) theme.applyTheme(this) currentNightMode = nightMode - currentPro = inventory.hasPro() + currentPro = inventory.hasPro binding = TaskListActivityBinding.inflate(layoutInflater) setContentView(binding.root) if (savedInstanceState != null) { @@ -329,7 +329,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl override fun onResume() { super.onResume() - if (currentNightMode != nightMode || currentPro != inventory.hasPro()) { + if (currentNightMode != nightMode || currentPro != inventory.hasPro) { recreate() return } diff --git a/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.kt b/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.kt index 2c942c142..0343f1bf9 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/FilterViewHolder.kt @@ -86,7 +86,7 @@ class FilterViewHolder internal constructor( } private fun getIcon(filter: FilterListItem): Int { - if (filter.icon < 1000 || inventory.hasPro()) { + if (filter.icon < 1000 || inventory.hasPro) { val icon = getIconResId(filter.icon) if (icon != null) { return icon diff --git a/app/src/main/java/org/tasks/billing/Inventory.java b/app/src/main/java/org/tasks/billing/Inventory.java deleted file mode 100644 index 03322a821..000000000 --- a/app/src/main/java/org/tasks/billing/Inventory.java +++ /dev/null @@ -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 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 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); - } -} diff --git a/app/src/main/java/org/tasks/billing/Inventory.kt b/app/src/main/java/org/tasks/billing/Inventory.kt new file mode 100644 index 000000000..a9b8743d9 --- /dev/null +++ b/app/src/main/java/org/tasks/billing/Inventory.kt @@ -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 = HashMap() + + fun clear() { + Timber.d("clear()") + purchases.clear() + } + + fun add(purchases: Iterable) { + verifyAndAdd(purchases) + preferences.setPurchases(this.purchases.values) + localBroadcastManager.broadcastPurchasesUpdated() + } + + private fun verifyAndAdd(items: Iterable) { + 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) + } +} diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt index f19e6e514..c3a8d087d 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt @@ -93,7 +93,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.showSoftInput(binding.name, InputMethodManager.SHOW_IMPLICIT) } - if (!inventory.hasPro()) { + if (!inventory.hasPro) { newSnackbar(getString(R.string.this_feature_requires_a_subscription)) .setDuration(BaseTransientBottomBar.LENGTH_INDEFINITE) .setAction(R.string.button_subscribe) { diff --git a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.kt b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.kt index 8f7b19a9b..1077bb859 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.kt +++ b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.kt @@ -64,7 +64,7 @@ class CaldavSynchronizer @Inject constructor( suspend fun sync(account: CaldavAccount) { Thread.currentThread().contextClassLoader = context.classLoader - if (!inventory.hasPro()) { + if (!inventory.hasPro) { setError(account, context.getString(R.string.requires_pro_subscription)) return } diff --git a/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt b/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt index 2c0dd7d79..ae3d74563 100644 --- a/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt +++ b/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt @@ -87,7 +87,7 @@ class ColorWheelPicker : DialogFragment() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == org.tasks.dialogs.REQUEST_PURCHASE) { - if (inventory.hasPro()) { + if (inventory.hasPro) { deliverSelection() } else { dialog?.cancel() diff --git a/app/src/main/java/org/tasks/dialogs/IconPickerAdapter.java b/app/src/main/java/org/tasks/dialogs/IconPickerAdapter.java index 1cc607ddb..10a15d57a 100644 --- a/app/src/main/java/org/tasks/dialogs/IconPickerAdapter.java +++ b/app/src/main/java/org/tasks/dialogs/IconPickerAdapter.java @@ -46,7 +46,7 @@ class IconPickerAdapter extends ListAdapter { int tint = index == current ? getData(activity, R.attr.colorAccent) : activity.getColor(R.color.icon_tint); - boolean available = index < 1000 || inventory.hasPro(); + boolean available = index < 1000 || inventory.getHasPro(); float alpha = ResourcesCompat.getFloat( activity.getResources(), diff --git a/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java b/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java index 95f9af2ac..b9099e22a 100644 --- a/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java +++ b/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java @@ -61,7 +61,7 @@ public class IconPickerDialog extends DialogFragment { AlertDialogBuilder builder = dialogBuilder.newDialog().setNegativeButton(R.string.cancel, null).setView(view); - if (!inventory.hasPro()) { + if (!inventory.getHasPro()) { builder.setPositiveButton( R.string.button_subscribe, (dialog, which) -> context.startActivity(new Intent(context, PurchaseActivity.class))); diff --git a/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt b/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt index 3cca55bfb..412a06b80 100644 --- a/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt +++ b/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt @@ -49,7 +49,7 @@ class WhatsNewDialog : DialogFragment() { val begForRating = !preferences.getBoolean(R.string.p_clicked_rate, false) && (inventory.purchasedThemes() || firebase.noChurn()) - val begForSubscription = firebase.noChurn() && !inventory.hasPro() + val begForSubscription = firebase.noChurn() && !inventory.hasPro when { BuildConfig.FLAVOR == "generic" -> { @@ -120,7 +120,7 @@ class WhatsNewDialog : DialogFragment() { Pair(R.string.param_click, click), Pair(R.string.param_whats_new_display_rate, displayedRate), Pair(R.string.param_whats_new_display_subscribe, displayedSubscribe), - Pair(R.string.param_user_pro, inventory.hasPro()), + Pair(R.string.param_user_pro, inventory.hasPro), Pair(R.string.param_user_no_churn, firebase.noChurn())) } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/etesync/EteSynchronizer.kt b/app/src/main/java/org/tasks/etesync/EteSynchronizer.kt index d572054cd..9a1fc01e6 100644 --- a/app/src/main/java/org/tasks/etesync/EteSynchronizer.kt +++ b/app/src/main/java/org/tasks/etesync/EteSynchronizer.kt @@ -50,7 +50,7 @@ class EteSynchronizer @Inject constructor( suspend fun sync(account: CaldavAccount) { Thread.currentThread().contextClassLoader = context.classLoader - if (!inventory.hasPro()) { + if (!inventory.hasPro) { setError(account, context.getString(R.string.requires_pro_subscription)) return } diff --git a/app/src/main/java/org/tasks/filters/FilterProvider.kt b/app/src/main/java/org/tasks/filters/FilterProvider.kt index 7cb51c863..2f4d772c6 100644 --- a/app/src/main/java/org/tasks/filters/FilterProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterProvider.kt @@ -175,7 +175,7 @@ class FilterProvider @Inject constructor( R.drawable.ic_outline_attach_money_24px, NavigationDrawerFragment.REQUEST_DONATE) } - .plusIf(!inventory.hasPro()) { + .plusIf(!inventory.hasPro) { NavigationDrawerAction( context.getString(R.string.name_your_price), R.drawable.ic_outline_attach_money_24px, diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt index dfa4c4416..41bdfa1b6 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt @@ -60,7 +60,7 @@ class GoogleTaskSynchronizer @Inject constructor( suspend fun sync(account: GoogleTaskAccount, i: Int) { Timber.d("%s: start sync", account) try { - if (i == 0 || inventory.hasPro()) { + if (i == 0 || inventory.hasPro) { synchronize(account) } else { account.error = context.getString(R.string.requires_pro_subscription) diff --git a/app/src/main/java/org/tasks/location/LocationPickerAdapter.java b/app/src/main/java/org/tasks/location/LocationPickerAdapter.java index 9dcee797a..0081001cd 100644 --- a/app/src/main/java/org/tasks/location/LocationPickerAdapter.java +++ b/app/src/main/java/org/tasks/location/LocationPickerAdapter.java @@ -73,7 +73,7 @@ public class LocationPickerAdapter extends ListAdapter) { + setPurchases(purchases.map(Purchase::toJson).toHashSet()) + } + + fun setPurchases(set: HashSet) { try { val editor = prefs.edit() - editor.putStringSet( - context.getString(R.string.p_purchases), - purchases.map(Purchase::toJson).toHashSet()) + editor.putStringSet(context.getString(R.string.p_purchases), set) editor.apply() } catch (e: Exception) { Timber.e(e) diff --git a/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt b/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt index 72c01565a..e1d51ded5 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt @@ -76,7 +76,7 @@ class HelpAndFeedback : InjectingPreferenceFragment() { if (BuildConfig.FLAVOR != "generic") { val findPreference = findPreference(R.string.upgrade_to_pro) - if (inventory.hasPro()) { + if (inventory.hasPro) { findPreference.title = getString(R.string.manage_subscription) findPreference.summary = getString(R.string.manage_subscription_summary) } diff --git a/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt b/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt index dbf6800ba..4227d40cf 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt @@ -190,7 +190,7 @@ class LookAndFeel : InjectingPreferenceFragment() { dialog.dismiss() return@setSingleChoiceItems } - if (!inventory.hasPro()) { + if (!inventory.hasPro) { toaster.longToast(R.string.requires_pro_subscription) dialog.dismiss() return@setSingleChoiceItems @@ -209,7 +209,7 @@ class LookAndFeel : InjectingPreferenceFragment() { } private fun getPlaceProvider(): Int { - return if (playServices.isPlayServicesAvailable && inventory.hasPro()) preferences.getInt( + return if (playServices.isPlayServicesAvailable && inventory.hasPro) preferences.getInt( R.string.p_place_provider, 0 ) else 0 @@ -228,7 +228,7 @@ class LookAndFeel : InjectingPreferenceFragment() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == REQUEST_PURCHASE) { - val index = if (inventory.hasPro()) { + val index = if (inventory.hasPro) { data?.getIntExtra(ThemePickerDialog.EXTRA_SELECTED, DEFAULT_BASE_THEME) ?: themeBase.index } else { diff --git a/app/src/main/java/org/tasks/tags/TagRecyclerAdapter.kt b/app/src/main/java/org/tasks/tags/TagRecyclerAdapter.kt index ef2554936..1c9d444a1 100644 --- a/app/src/main/java/org/tasks/tags/TagRecyclerAdapter.kt +++ b/app/src/main/java/org/tasks/tags/TagRecyclerAdapter.kt @@ -46,7 +46,7 @@ internal class TagRecyclerAdapter( } private fun getIcon(tagData: TagData): Int? { - return if (tagData.getIcon()!! < 1000 || inventory.hasPro()) getIconResId(tagData.getIcon()!!) else null + return if (tagData.getIcon()!! < 1000 || inventory.hasPro) getIconResId(tagData.getIcon()!!) else null } fun submitList(tagData: List?) {