Convert Inventory to Kotlin

pull/1200/head
Alex Baker 5 years ago
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\"}"
}
}

@ -7,7 +7,7 @@ import timber.log.Timber
import java.io.IOException import java.io.IOException
import javax.inject.Inject 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) private val billingKey: String = context.getString(R.string.gp_key)
fun verifySignature(purchase: Purchase): Boolean { fun verifySignature(purchase: Purchase): Boolean {

@ -24,7 +24,7 @@ internal class LocationModule {
inventory: Inventory): PlaceSearchProvider { inventory: Inventory): PlaceSearchProvider {
return if (preferences.useGooglePlaces() return if (preferences.useGooglePlaces()
&& playServices.isPlayServicesAvailable && playServices.isPlayServicesAvailable
&& inventory.hasPro()) { && inventory.hasPro) {
GooglePlacesSearchProvider(context) GooglePlacesSearchProvider(context)
} else { } else {
MapboxSearchProvider(context) MapboxSearchProvider(context)

@ -86,7 +86,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
theme.applyTheme(this) theme.applyTheme(this)
currentNightMode = nightMode currentNightMode = nightMode
currentPro = inventory.hasPro() currentPro = inventory.hasPro
binding = TaskListActivityBinding.inflate(layoutInflater) binding = TaskListActivityBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
if (savedInstanceState != null) { if (savedInstanceState != null) {
@ -329,7 +329,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (currentNightMode != nightMode || currentPro != inventory.hasPro()) { if (currentNightMode != nightMode || currentPro != inventory.hasPro) {
recreate() recreate()
return return
} }

@ -86,7 +86,7 @@ class FilterViewHolder internal constructor(
} }
private fun getIcon(filter: FilterListItem): Int { private fun getIcon(filter: FilterListItem): Int {
if (filter.icon < 1000 || inventory.hasPro()) { if (filter.icon < 1000 || inventory.hasPro) {
val icon = getIconResId(filter.icon) val icon = getIconResId(filter.icon)
if (icon != null) { if (icon != null) {
return icon return icon

@ -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)
}
}

@ -93,7 +93,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(binding.name, InputMethodManager.SHOW_IMPLICIT) imm.showSoftInput(binding.name, InputMethodManager.SHOW_IMPLICIT)
} }
if (!inventory.hasPro()) { if (!inventory.hasPro) {
newSnackbar(getString(R.string.this_feature_requires_a_subscription)) newSnackbar(getString(R.string.this_feature_requires_a_subscription))
.setDuration(BaseTransientBottomBar.LENGTH_INDEFINITE) .setDuration(BaseTransientBottomBar.LENGTH_INDEFINITE)
.setAction(R.string.button_subscribe) { .setAction(R.string.button_subscribe) {

@ -64,7 +64,7 @@ class CaldavSynchronizer @Inject constructor(
suspend fun sync(account: CaldavAccount) { suspend fun sync(account: CaldavAccount) {
Thread.currentThread().contextClassLoader = context.classLoader Thread.currentThread().contextClassLoader = context.classLoader
if (!inventory.hasPro()) { if (!inventory.hasPro) {
setError(account, context.getString(R.string.requires_pro_subscription)) setError(account, context.getString(R.string.requires_pro_subscription))
return return
} }

@ -87,7 +87,7 @@ class ColorWheelPicker : DialogFragment() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == org.tasks.dialogs.REQUEST_PURCHASE) { if (requestCode == org.tasks.dialogs.REQUEST_PURCHASE) {
if (inventory.hasPro()) { if (inventory.hasPro) {
deliverSelection() deliverSelection()
} else { } else {
dialog?.cancel() dialog?.cancel()

@ -46,7 +46,7 @@ class IconPickerAdapter extends ListAdapter<Integer, IconPickerHolder> {
int tint = index == current int tint = index == current
? getData(activity, R.attr.colorAccent) ? getData(activity, R.attr.colorAccent)
: activity.getColor(R.color.icon_tint); : activity.getColor(R.color.icon_tint);
boolean available = index < 1000 || inventory.hasPro(); boolean available = index < 1000 || inventory.getHasPro();
float alpha = float alpha =
ResourcesCompat.getFloat( ResourcesCompat.getFloat(
activity.getResources(), activity.getResources(),

@ -61,7 +61,7 @@ public class IconPickerDialog extends DialogFragment {
AlertDialogBuilder builder = AlertDialogBuilder builder =
dialogBuilder.newDialog().setNegativeButton(R.string.cancel, null).setView(view); dialogBuilder.newDialog().setNegativeButton(R.string.cancel, null).setView(view);
if (!inventory.hasPro()) { if (!inventory.getHasPro()) {
builder.setPositiveButton( builder.setPositiveButton(
R.string.button_subscribe, R.string.button_subscribe,
(dialog, which) -> context.startActivity(new Intent(context, PurchaseActivity.class))); (dialog, which) -> context.startActivity(new Intent(context, PurchaseActivity.class)));

@ -49,7 +49,7 @@ class WhatsNewDialog : DialogFragment() {
val begForRating = !preferences.getBoolean(R.string.p_clicked_rate, false) val begForRating = !preferences.getBoolean(R.string.p_clicked_rate, false)
&& (inventory.purchasedThemes() || firebase.noChurn()) && (inventory.purchasedThemes() || firebase.noChurn())
val begForSubscription = firebase.noChurn() && !inventory.hasPro() val begForSubscription = firebase.noChurn() && !inventory.hasPro
when { when {
BuildConfig.FLAVOR == "generic" -> { BuildConfig.FLAVOR == "generic" -> {
@ -120,7 +120,7 @@ class WhatsNewDialog : DialogFragment() {
Pair(R.string.param_click, click), Pair(R.string.param_click, click),
Pair(R.string.param_whats_new_display_rate, displayedRate), Pair(R.string.param_whats_new_display_rate, displayedRate),
Pair(R.string.param_whats_new_display_subscribe, displayedSubscribe), 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())) Pair(R.string.param_user_no_churn, firebase.noChurn()))
} }
} }

@ -50,7 +50,7 @@ class EteSynchronizer @Inject constructor(
suspend fun sync(account: CaldavAccount) { suspend fun sync(account: CaldavAccount) {
Thread.currentThread().contextClassLoader = context.classLoader Thread.currentThread().contextClassLoader = context.classLoader
if (!inventory.hasPro()) { if (!inventory.hasPro) {
setError(account, context.getString(R.string.requires_pro_subscription)) setError(account, context.getString(R.string.requires_pro_subscription))
return return
} }

@ -175,7 +175,7 @@ class FilterProvider @Inject constructor(
R.drawable.ic_outline_attach_money_24px, R.drawable.ic_outline_attach_money_24px,
NavigationDrawerFragment.REQUEST_DONATE) NavigationDrawerFragment.REQUEST_DONATE)
} }
.plusIf(!inventory.hasPro()) { .plusIf(!inventory.hasPro) {
NavigationDrawerAction( NavigationDrawerAction(
context.getString(R.string.name_your_price), context.getString(R.string.name_your_price),
R.drawable.ic_outline_attach_money_24px, R.drawable.ic_outline_attach_money_24px,

@ -60,7 +60,7 @@ class GoogleTaskSynchronizer @Inject constructor(
suspend fun sync(account: GoogleTaskAccount, i: Int) { suspend fun sync(account: GoogleTaskAccount, i: Int) {
Timber.d("%s: start sync", account) Timber.d("%s: start sync", account)
try { try {
if (i == 0 || inventory.hasPro()) { if (i == 0 || inventory.hasPro) {
synchronize(account) synchronize(account)
} else { } else {
account.error = context.getString(R.string.requires_pro_subscription) account.error = context.getString(R.string.requires_pro_subscription)

@ -73,7 +73,7 @@ public class LocationPickerAdapter extends ListAdapter<PlaceUsage, PlaceViewHold
} }
private int getIcon(int index) { private int getIcon(int index) {
if (index < 1000 || inventory.hasPro()) { if (index < 1000 || inventory.getHasPro()) {
Integer icon = CustomIcons.getIconResId(index); Integer icon = CustomIcons.getIconResId(index);
if (icon != null) { if (icon != null) {
return icon; return icon;

@ -83,7 +83,7 @@ class OpenTasksSynchronizer @Inject constructor(
val entries = lists[account.uuid!!] val entries = lists[account.uuid!!]
if (entries == null) { if (entries == null) {
taskDeleter.delete(account) taskDeleter.delete(account)
} else if (!inventory.hasPro()) { } else if (!inventory.hasPro) {
setError(account, context.getString(R.string.requires_pro_subscription)) setError(account, context.getString(R.string.requires_pro_subscription))
} else { } else {
sync(account, entries) sync(account, entries)

@ -115,11 +115,13 @@ class Preferences @JvmOverloads constructor(
} }
fun setPurchases(purchases: Collection<Purchase>) { fun setPurchases(purchases: Collection<Purchase>) {
setPurchases(purchases.map(Purchase::toJson).toHashSet())
}
fun setPurchases(set: HashSet<String>) {
try { try {
val editor = prefs.edit() val editor = prefs.edit()
editor.putStringSet( editor.putStringSet(context.getString(R.string.p_purchases), set)
context.getString(R.string.p_purchases),
purchases.map(Purchase::toJson).toHashSet())
editor.apply() editor.apply()
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e) Timber.e(e)

@ -76,7 +76,7 @@ class HelpAndFeedback : InjectingPreferenceFragment() {
if (BuildConfig.FLAVOR != "generic") { if (BuildConfig.FLAVOR != "generic") {
val findPreference = findPreference(R.string.upgrade_to_pro) val findPreference = findPreference(R.string.upgrade_to_pro)
if (inventory.hasPro()) { if (inventory.hasPro) {
findPreference.title = getString(R.string.manage_subscription) findPreference.title = getString(R.string.manage_subscription)
findPreference.summary = getString(R.string.manage_subscription_summary) findPreference.summary = getString(R.string.manage_subscription_summary)
} }

@ -190,7 +190,7 @@ class LookAndFeel : InjectingPreferenceFragment() {
dialog.dismiss() dialog.dismiss()
return@setSingleChoiceItems return@setSingleChoiceItems
} }
if (!inventory.hasPro()) { if (!inventory.hasPro) {
toaster.longToast(R.string.requires_pro_subscription) toaster.longToast(R.string.requires_pro_subscription)
dialog.dismiss() dialog.dismiss()
return@setSingleChoiceItems return@setSingleChoiceItems
@ -209,7 +209,7 @@ class LookAndFeel : InjectingPreferenceFragment() {
} }
private fun getPlaceProvider(): Int { 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, R.string.p_place_provider,
0 0
) else 0 ) else 0
@ -228,7 +228,7 @@ class LookAndFeel : InjectingPreferenceFragment() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_PURCHASE) { if (requestCode == REQUEST_PURCHASE) {
val index = if (inventory.hasPro()) { val index = if (inventory.hasPro) {
data?.getIntExtra(ThemePickerDialog.EXTRA_SELECTED, DEFAULT_BASE_THEME) data?.getIntExtra(ThemePickerDialog.EXTRA_SELECTED, DEFAULT_BASE_THEME)
?: themeBase.index ?: themeBase.index
} else { } else {

@ -46,7 +46,7 @@ internal class TagRecyclerAdapter(
} }
private fun getIcon(tagData: TagData): Int? { 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<TagData>?) { fun submitList(tagData: List<TagData>?) {

Loading…
Cancel
Save