diff --git a/app/src/googleplay/java/org/tasks/billing/Purchase.kt b/app/src/googleplay/java/org/tasks/billing/Purchase.kt index 2aef951ca..8bd7e73e9 100644 --- a/app/src/googleplay/java/org/tasks/billing/Purchase.kt +++ b/app/src/googleplay/java/org/tasks/billing/Purchase.kt @@ -48,6 +48,6 @@ class Purchase(private val purchase: Purchase) { } companion object { - private val PATTERN = Pattern.compile("^(annual|monthly)_([0-1][0-9]|499)$") + private val PATTERN = Pattern.compile("^(annual|monthly)_([0-3][0-9]|499)$") } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d7f0fd4e7..1994bd33a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -532,10 +532,6 @@ android:uiOptions="splitActionBarWhenNarrow" android:windowSoftInputMode="adjustResize"/> - - this.onButtonChecked(group!!, id, checked) } - - val toolbar = binding.toolbar.toolbar - toolbar.setNavigationIcon(R.drawable.ic_outline_arrow_back_24px) - toolbar.setNavigationContentDescription(R.string.back) - toolbar.setNavigationOnClickListener { finish() } - toolbar.setTitle(R.string.upgrade_to_pro) - toolbar.inflateMenu(R.menu.menu_purchase_activity) - toolbar.setOnMenuItemClickListener(this) - - themeColor.apply(toolbar) - - setWaitScreen(true) - } - - @SuppressLint("DefaultLocale") - @OnClick(R.id.subscribe) - fun subscribe() { - if (currentSubscriptionSelected() && currentSubscription?.isCanceled == true) { - billingClient.initiatePurchaseFlow( - this, currentSubscription!!.sku, BillingClientImpl.TYPE_SUBS, null) - } else { - billingClient.initiatePurchaseFlow(this, String.format("%s_%02d", if (isMonthly()) "monthly" else "annual", adapter.selected), - BillingClientImpl.TYPE_SUBS, - currentSubscription?.sku) - } - billingClient.addPurchaseCallback(this) - } - - private fun onButtonChecked(group: MaterialButtonToggleGroup, id: Int, checked: Boolean) { - if (id == R.id.button_monthly) { - if (!checked && group.checkedButtonId != R.id.button_annually) { - group.check(R.id.button_monthly) - } - } else { - if (!checked && group.checkedButtonId != R.id.button_monthly) { - group.check(R.id.button_annually) - } - } - updateSubscribeButton() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putBoolean(EXTRA_MONTHLY, isMonthly()) - outState.putInt(EXTRA_PRICE, adapter.selected) - } - - private fun isMonthly() = binding.buttons.checkedButtonId == R.id.button_monthly - - private fun setWaitScreen(isWaitScreen: Boolean) { - Timber.d("setWaitScreen(%s)", isWaitScreen) - binding.recyclerView.visibility = if (isWaitScreen) View.GONE else View.VISIBLE - binding.buttons.visibility = if (isWaitScreen) View.GONE else View.VISIBLE - binding.subscribe.visibility = if (isWaitScreen) View.GONE else View.VISIBLE - binding.screenWait.visibility = if (isWaitScreen) View.VISIBLE else View.GONE - } - - override fun onStart() { - super.onStart() - localBroadcastManager.registerPurchaseReceiver(purchaseReceiver) - billingClient.queryPurchases() - } - - override fun onStop() { - super.onStop() - localBroadcastManager.unregisterReceiver(purchaseReceiver) - } - - private fun setup() { - currentSubscription = inventory.subscription - if (adapter.selected == 0) { - adapter.selected = currentSubscription?.subscriptionPrice ?: 3 - if (currentSubscription != null) { - binding.buttons.check(if (currentSubscription?.isMonthly == true) R.id.button_monthly else R.id.button_annually) - } - } - binding.unsubscribe.visibility = if (currentSubscription == null || currentSubscription?.isCanceled == true) View.GONE else View.VISIBLE - updateSubscribeButton() - setWaitScreen(false) - adapter.submitList((1..15).toList()) - binding.recyclerView.layoutManager = IconLayoutManager(this) - binding.recyclerView.adapter = adapter - } - - private fun updateSubscribeButton() { - binding.subscribe.isEnabled = true - if (currentSubscription == null) { - binding.subscribe.setText(R.string.button_subscribe) - } else if (currentSubscriptionSelected()) { - if (currentSubscription!!.isCanceled) { - binding.subscribe.setText(R.string.button_restore_subscription) - } else { - binding.subscribe.setText(R.string.button_current_subscription) - binding.subscribe.isEnabled = false - } - } else { - binding.subscribe.setText(if (isUpgrade()) R.string.button_upgrade else R.string.button_downgrade) - } - } - - private fun currentSubscriptionSelected() = - currentSubscription != null - && isMonthly() == currentSubscription!!.isMonthly - && adapter.selected == currentSubscription!!.subscriptionPrice - - private fun isUpgrade() = if (isMonthly() == currentSubscription!!.isMonthly) { - currentSubscription!!.subscriptionPrice!! < adapter.selected - } else { - isMonthly() - } - - private fun onPriceChanged(price: Int) { - adapter.selected = price - updateSubscribeButton() - } - - @OnClick(R.id.unsubscribe) - fun manageSubscription() { - startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(getString(R.string.manage_subscription_url, currentSubscription!!.sku)))) - } - - override fun onPurchasesUpdated(success: Boolean) { - if (success) { - finish() - } - } - - override fun onMenuItemClick(item: MenuItem?): Boolean { - return if (item?.itemId == R.id.menu_more_info) { - startActivity( - Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.subscription_help_url)))) - true - } else { - false - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/billing/PurchaseAdapter.java b/app/src/main/java/org/tasks/billing/PurchaseAdapter.java deleted file mode 100644 index baf287319..000000000 --- a/app/src/main/java/org/tasks/billing/PurchaseAdapter.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.tasks.billing; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.DiffUtil.ItemCallback; -import androidx.recyclerview.widget.ListAdapter; -import org.tasks.Callback; -import org.tasks.R; -import org.tasks.locale.Locale; -import org.tasks.themes.Theme; - -public class PurchaseAdapter extends ListAdapter { - - private final Context context; - private final Theme theme; - private final Locale locale; - private final Callback onPriceChanged; - private int selected; - - PurchaseAdapter(Context context, Theme theme, Locale locale, Callback onPriceChanged) { - super(new DiffCallback()); - this.context = context; - this.theme = theme; - this.locale = locale; - this.onPriceChanged = onPriceChanged; - } - - public int getSelected() { - return selected; - } - - public void setSelected(int price) { - int previous = selected; - this.selected = price; - notifyItemChanged(previous - 1, null); - notifyItemChanged(price - 1, null); - } - - @NonNull - @Override - public PurchaseHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = - theme.getLayoutInflater(context).inflate(R.layout.dialog_purchase_cell, parent, false); - return new PurchaseHolder(view, onPriceChanged, locale); - } - - @Override - public void onBindViewHolder(@NonNull PurchaseHolder holder, int position) { - int price = position + 1; - holder.bind(price, price == selected); - } - - private static class DiffCallback extends ItemCallback { - @Override - public boolean areItemsTheSame(@NonNull Integer oldItem, @NonNull Integer newItem) { - return oldItem.equals(newItem); - } - - @Override - public boolean areContentsTheSame(@NonNull Integer oldItem, @NonNull Integer newItem) { - return true; - } - } -} diff --git a/app/src/main/java/org/tasks/billing/PurchaseDialog.kt b/app/src/main/java/org/tasks/billing/PurchaseDialog.kt new file mode 100644 index 000000000..a5f1e150f --- /dev/null +++ b/app/src/main/java/org/tasks/billing/PurchaseDialog.kt @@ -0,0 +1,250 @@ +package org.tasks.billing + +import android.app.Activity.RESULT_OK +import android.app.Dialog +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.text.method.LinkMovementMethod +import androidx.core.view.isVisible +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.Fragment +import butterknife.ButterKnife +import butterknife.OnClick +import com.google.android.material.slider.Slider +import dagger.hilt.android.AndroidEntryPoint +import io.noties.markwon.Markwon +import io.noties.markwon.ext.strikethrough.StrikethroughPlugin +import org.tasks.LocalBroadcastManager +import org.tasks.R +import org.tasks.databinding.ActivityPurchaseBinding +import org.tasks.dialogs.DialogBuilder +import org.tasks.locale.Locale +import org.tasks.themes.Theme +import timber.log.Timber +import javax.inject.Inject + +@AndroidEntryPoint +class PurchaseDialog : DialogFragment(), OnPurchasesUpdated { + + private val purchaseReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + setup() + } + } + + @Inject lateinit var tasksTheme: Theme + @Inject lateinit var inventory: Inventory + @Inject lateinit var dialogBuilder: DialogBuilder + @Inject lateinit var billingClient: BillingClient + @Inject lateinit var localBroadcastManager: LocalBroadcastManager + @Inject lateinit var locale: Locale + + private lateinit var binding: ActivityPurchaseBinding + private lateinit var markwon: Markwon + + private var currentSubscription: Purchase? = null + private var priceChanged = false + private var nameYourPrice = false + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + binding = ActivityPurchaseBinding.inflate(layoutInflater) + ButterKnife.bind(this, binding.root) + + if (savedInstanceState != null) { + binding.slider.value = savedInstanceState.getFloat(EXTRA_PRICE) + priceChanged = savedInstanceState.getBoolean(EXTRA_PRICE_CHANGED) + nameYourPrice = savedInstanceState.getBoolean(EXTRA_NAME_YOUR_PRICE) + } + + binding.slider.addOnChangeListener(this::onPriceChanged) + binding.slider.setLabelFormatter { + "$${it - .01}" + } + binding.text.movementMethod = LinkMovementMethod.getInstance() + + markwon = Markwon.builder(requireContext()) + .usePlugin(StrikethroughPlugin.create()) + .build() + + setWaitScreen(true) + + return dialogBuilder.newDialog() + .setView(binding.root) + .show() + } + + private fun updateText() { + var benefits = "### ${getString(R.string.upgrade_header)}" + if (nameYourPrice) { + benefits += """ +--- +#### ~~${getString(R.string.upgrade_sync_with_tasks)}~~ +""" + } else { + benefits += """ +--- +#### [${getString(R.string.upgrade_sync_with_tasks)} (BETA)](https://tasks.org/sync) +* **${getString(R.string.upgrade_no_platform_lock_in)}** — ${getString(R.string.upgrade_open_internet_standards)} +* **${getString(R.string.upgrade_customer)}** — ${getString(R.string.upgrade_privacy)} +* ${getString(R.string.upgrade_coming_soon)} +""" + } + benefits += """ +--- +#### ${getString(R.string.upgrade_synchronization)} +* [${getString(R.string.davx5)}](https://tasks.org/docs/davx5.html) +* [${getString(R.string.caldav)}](https://tasks.org/docs/caldav_intro.html) +* [${getString(R.string.upgrade_etesync)}](https://tasks.org/docs/etesync_intro.html) +* ${getString(R.string.upgrade_google_tasks)} +--- +#### ${getString(R.string.upgrade_additional_features)} +* ${getString(R.string.upgrade_themes)} +* ${getString(R.string.upgrade_google_places)} +* [${getString(R.string.upgrade_tasker)}](https://tasks.org/docs/tasker.html) +--- +* ${getString(R.string.upgrade_free_trial)} +* **${getString(R.string.upgrade_downgrade)}** — ${getString(R.string.upgrade_balance)} +* **${getString(R.string.upgrade_cancel)}** — ${getString(R.string.upgrade_benefits_retained)} +""" + + binding.text.text = markwon.toMarkdown(benefits) + } + + @OnClick(R.id.pay_annually) + fun subscribeAnnually() { + initiatePurchase(false, 30) + } + + @OnClick(R.id.pay_monthly) + fun subscribeMonthly() { + initiatePurchase(true, 3) + } + + private fun initiatePurchase(isMonthly: Boolean, price: Int) { + val newSku = String.format("%s_%02d", if (isMonthly) "monthly" else "annual", price) + billingClient.initiatePurchaseFlow( + requireActivity(), + newSku, + BillingClientImpl.TYPE_SUBS, + currentSubscription?.sku?.takeIf { it != newSku }) + billingClient.addPurchaseCallback(this) + } + + @OnClick(R.id.pay_other) + fun nameYourPrice() { + nameYourPrice = !nameYourPrice + setWaitScreen(false) + binding.scroll.scrollTo(0, 0) + updateSubscribeButton() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putFloat(EXTRA_PRICE, binding.slider.value) + outState.putBoolean(EXTRA_PRICE_CHANGED, priceChanged) + outState.putBoolean(EXTRA_NAME_YOUR_PRICE, nameYourPrice) + } + + private fun setWaitScreen(isWaitScreen: Boolean) { + Timber.d("setWaitScreen(%s)", isWaitScreen) + binding.slider.isVisible = !isWaitScreen && nameYourPrice + binding.payOther.isVisible = !isWaitScreen + binding.payOther.setText(if (nameYourPrice) R.string.back else R.string.more_options) + binding.tasksOrgButtonPanel.isVisible = !isWaitScreen + binding.screenWait.isVisible = isWaitScreen + updateText() + } + + override fun onStart() { + super.onStart() + localBroadcastManager.registerPurchaseReceiver(purchaseReceiver) + billingClient.queryPurchases() + } + + override fun onStop() { + super.onStop() + localBroadcastManager.unregisterReceiver(purchaseReceiver) + } + + private fun setup() { + currentSubscription = inventory.subscription + if (!priceChanged) { + binding.slider.value = + currentSubscription + ?.subscriptionPrice + ?.coerceAtMost(25) + ?.toFloat() ?: 10f + } + updateSubscribeButton() + setWaitScreen(false) + } + + private fun updateSubscribeButton() { + val sliderValue = binding.slider.value.toInt() + val annualPrice = if (nameYourPrice) sliderValue else 30 + val monthlyPrice = if (nameYourPrice) sliderValue else 3 + val constrained = resources.getBoolean(R.bool.width_constrained) + binding.payAnnually.let { + it.isEnabled = true + it.text = getString( + if (constrained) R.string.price_per_year_abbreviated else R.string.price_per_year, + annualPrice - .01 + ) + it.setOnClickListener { + initiatePurchase(false, if (nameYourPrice) sliderValue else 30) + } + } + binding.payMonthly.let { + it.isEnabled = true + it.text = getString( + if (constrained) R.string.price_per_month_abbreviated else R.string.price_per_month, + monthlyPrice - .01 + ) + it.setOnClickListener { + initiatePurchase(true, if (nameYourPrice) sliderValue else 3) + } + it.isVisible = !nameYourPrice || sliderValue < 3 + } + currentSubscription?.let { + binding.payMonthly.isEnabled = + it.isCanceled || !it.isMonthly || monthlyPrice != it.subscriptionPrice + binding.payAnnually.isEnabled = + it.isCanceled || it.isMonthly || annualPrice != it.subscriptionPrice + } + } + + private fun onPriceChanged(slider: Slider, value: Float, fromUser: Boolean) { + if (fromUser) { + priceChanged = true + } + updateSubscribeButton() + } + + override fun onPurchasesUpdated(success: Boolean) { + if (success) { + dismiss() + targetFragment?.onActivityResult(targetRequestCode, RESULT_OK, null) + } + } + + companion object { + private const val EXTRA_PRICE = "extra_price" + private const val EXTRA_PRICE_CHANGED = "extra_price_changed" + private const val EXTRA_NAME_YOUR_PRICE = "extra_name_your_price" + @JvmStatic + val FRAG_TAG_PURCHASE_DIALOG = "frag_tag_purchase_dialog" + + @JvmStatic + fun newPurchaseDialog(): PurchaseDialog { + return PurchaseDialog() + } + + fun newPurchaseDialog(target: Fragment, rc: Int): PurchaseDialog { + val dialog = PurchaseDialog() + dialog.setTargetFragment(target, rc) + return dialog + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/billing/PurchaseHolder.java b/app/src/main/java/org/tasks/billing/PurchaseHolder.java deleted file mode 100644 index 936a5510a..000000000 --- a/app/src/main/java/org/tasks/billing/PurchaseHolder.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.tasks.billing; - -import android.view.View; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import com.google.android.material.button.MaterialButton; -import org.tasks.Callback; -import org.tasks.R; -import org.tasks.locale.Locale; - -public class PurchaseHolder extends RecyclerView.ViewHolder { - - private final Callback onClick; - private final Locale locale; - - @BindView(R.id.price) - MaterialButton button; - - private int price; - - PurchaseHolder(@NonNull View view, Callback onClick, Locale locale) { - super(view); - this.locale = locale; - - ButterKnife.bind(this, view); - - this.onClick = onClick; - } - - @OnClick(R.id.price) - void onClick() { - onClick.call(price); - } - - public void bind(int price, boolean selected) { - this.price = price; - button.setText(String.format("$%s", locale.formatNumber(price))); - button.setChecked(selected); - } -} diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt index c3a8d087d..d844d005e 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavAccountSettingsActivity.kt @@ -25,7 +25,8 @@ import org.tasks.R import org.tasks.Strings.isNullOrEmpty import org.tasks.analytics.Firebase import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.data.CaldavAccount import org.tasks.data.CaldavDao import org.tasks.databinding.ActivityCaldavAccountSettingsBinding @@ -97,7 +98,7 @@ abstract class BaseCaldavAccountSettingsActivity : ThemedInjectingAppCompatActiv newSnackbar(getString(R.string.this_feature_requires_a_subscription)) .setDuration(BaseTransientBottomBar.LENGTH_INDEFINITE) .setAction(R.string.button_subscribe) { - startActivity(Intent(this, PurchaseActivity::class.java)) + newPurchaseDialog().show(supportFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } .show() } diff --git a/app/src/main/java/org/tasks/dialogs/ColorPalettePicker.kt b/app/src/main/java/org/tasks/dialogs/ColorPalettePicker.kt index 782eb070e..22f20b943 100644 --- a/app/src/main/java/org/tasks/dialogs/ColorPalettePicker.kt +++ b/app/src/main/java/org/tasks/dialogs/ColorPalettePicker.kt @@ -16,7 +16,8 @@ import butterknife.ButterKnife import dagger.hilt.android.AndroidEntryPoint import org.tasks.R import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.dialogs.ColorPickerAdapter.Palette import org.tasks.dialogs.ColorWheelPicker.Companion.newColorWheel import org.tasks.themes.ColorProvider @@ -107,7 +108,7 @@ class ColorPalettePicker : DialogFragment() { builder.setNegativeButton(R.string.cancel, null) } else { builder.setPositiveButton(R.string.button_subscribe) { _: DialogInterface?, _: Int -> - context?.startActivity(Intent(requireContext(), PurchaseActivity::class.java)) + newPurchaseDialog().show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } } return builder.show() diff --git a/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt b/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt index ae3d74563..f782d4028 100644 --- a/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt +++ b/app/src/main/java/org/tasks/dialogs/ColorWheelPicker.kt @@ -15,17 +15,16 @@ import com.flask.colorpicker.builder.ColorPickerDialogBuilder import dagger.hilt.android.AndroidEntryPoint import org.tasks.R import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity -import org.tasks.ui.NavigationDrawerFragment.Companion.REQUEST_PURCHASE +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import javax.inject.Inject -private const val REQUEST_PURCHASE = 10010 - @AndroidEntryPoint class ColorWheelPicker : DialogFragment() { companion object { const val EXTRA_SELECTED = "extra_selected" + private const val REQUEST_PURCHASE = 10010 fun newColorWheel(target: Fragment?, rc: Int, selected: Int): ColorWheelPicker { val args = Bundle() @@ -66,7 +65,8 @@ class ColorWheelPicker : DialogFragment() { if (inventory.purchasedThemes()) { deliverSelection() } else { - startActivityForResult(Intent(activity, PurchaseActivity::class.java), REQUEST_PURCHASE) + newPurchaseDialog(this, REQUEST_PURCHASE) + .show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } } .setNegativeButton(R.string.cancel, null) @@ -86,7 +86,7 @@ class ColorWheelPicker : DialogFragment() { } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == org.tasks.dialogs.REQUEST_PURCHASE) { + if (requestCode == REQUEST_PURCHASE) { if (inventory.hasPro) { deliverSelection() } else { diff --git a/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java b/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java index b9099e22a..3ae7613a7 100644 --- a/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java +++ b/app/src/main/java/org/tasks/dialogs/IconPickerDialog.java @@ -1,9 +1,10 @@ package org.tasks.dialogs; +import static org.tasks.billing.PurchaseDialog.newPurchaseDialog; + import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; -import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -17,7 +18,7 @@ import dagger.hilt.android.AndroidEntryPoint; import javax.inject.Inject; import org.tasks.R; import org.tasks.billing.Inventory; -import org.tasks.billing.PurchaseActivity; +import org.tasks.billing.PurchaseDialog; import org.tasks.themes.CustomIcons; @AndroidEntryPoint @@ -64,7 +65,8 @@ public class IconPickerDialog extends DialogFragment { if (!inventory.getHasPro()) { builder.setPositiveButton( R.string.button_subscribe, - (dialog, which) -> context.startActivity(new Intent(context, PurchaseActivity.class))); + (dialog, which) -> newPurchaseDialog() + .show(getParentFragmentManager(), PurchaseDialog.getFRAG_TAG_PURCHASE_DIALOG())); } return builder.show(); } diff --git a/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt b/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt index 412a06b80..b4a3be46d 100644 --- a/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt +++ b/app/src/main/java/org/tasks/dialogs/WhatsNewDialog.kt @@ -18,7 +18,8 @@ import org.tasks.BuildConfig import org.tasks.R import org.tasks.analytics.Firebase import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.preferences.Preferences import javax.inject.Inject @@ -88,7 +89,7 @@ class WhatsNewDialog : DialogFragment() { private fun onSubscribeClick() { logClick(true) dismiss() - startActivity(Intent(context, PurchaseActivity::class.java)) + newPurchaseDialog().show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } private fun onRateClick() { diff --git a/app/src/main/java/org/tasks/filters/FilterProvider.kt b/app/src/main/java/org/tasks/filters/FilterProvider.kt index 2f4d772c6..2caf37d03 100644 --- a/app/src/main/java/org/tasks/filters/FilterProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterProvider.kt @@ -177,7 +177,7 @@ class FilterProvider @Inject constructor( } .plusIf(!inventory.hasPro) { NavigationDrawerAction( - context.getString(R.string.name_your_price), + context.getString(R.string.upgrade_to_pro), R.drawable.ic_outline_attach_money_24px, NavigationDrawerFragment.REQUEST_PURCHASE) } diff --git a/app/src/main/java/org/tasks/locale/ui/activity/TaskerCreateTaskActivity.java b/app/src/main/java/org/tasks/locale/ui/activity/TaskerCreateTaskActivity.java index e95a1b90b..ddb2d5157 100755 --- a/app/src/main/java/org/tasks/locale/ui/activity/TaskerCreateTaskActivity.java +++ b/app/src/main/java/org/tasks/locale/ui/activity/TaskerCreateTaskActivity.java @@ -1,5 +1,7 @@ package org.tasks.locale.ui.activity; +import static org.tasks.billing.PurchaseDialog.newPurchaseDialog; + import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -11,7 +13,7 @@ import net.dinglisch.android.tasker.TaskerPlugin; import org.tasks.LocalBroadcastManager; import org.tasks.R; import org.tasks.billing.Inventory; -import org.tasks.billing.PurchaseActivity; +import org.tasks.billing.PurchaseDialog; import org.tasks.databinding.ActivityTaskerCreateBinding; import org.tasks.locale.bundle.TaskCreationBundle; @@ -53,7 +55,8 @@ public final class TaskerCreateTaskActivity extends AbstractFragmentPluginAppCom } private void showPurchaseDialog() { - startActivity(new Intent(this, PurchaseActivity.class)); + newPurchaseDialog() + .show(getSupportFragmentManager(), PurchaseDialog.getFRAG_TAG_PURCHASE_DIALOG()); } @Override 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 e1d51ded5..30578a066 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt @@ -9,6 +9,8 @@ import org.tasks.BuildConfig import org.tasks.R import org.tasks.billing.BillingClient import org.tasks.billing.Inventory +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.dialogs.WhatsNewDialog import org.tasks.injection.InjectingPreferenceFragment import javax.inject.Inject @@ -60,12 +62,28 @@ class HelpAndFeedback : InjectingPreferenceFragment() { true } + findPreference(R.string.button_unsubscribe).setOnPreferenceClickListener { + inventory.subscription?.let { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse(getString(R.string.manage_subscription_url, it.sku)))) + } + false + } + + findPreference(R.string.upgrade_to_pro).setOnPreferenceClickListener { + newPurchaseDialog().show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) + false + } + @Suppress("ConstantConditionIf") if (BuildConfig.FLAVOR == "generic") { remove( R.string.p_collect_statistics, R.string.rate_tasks, R.string.upgrade_to_pro, + R.string.button_unsubscribe, R.string.refresh_purchases ) } @@ -75,11 +93,12 @@ class HelpAndFeedback : InjectingPreferenceFragment() { super.onResume() if (BuildConfig.FLAVOR != "generic") { - val findPreference = findPreference(R.string.upgrade_to_pro) - if (inventory.hasPro) { - findPreference.title = getString(R.string.manage_subscription) - findPreference.summary = getString(R.string.manage_subscription_summary) - } + findPreference(R.string.upgrade_to_pro).title = getString(if (inventory.hasPro) { + R.string.manage_subscription + } else { + R.string.upgrade_to_pro + }) + findPreference(R.string.button_unsubscribe).isEnabled = inventory.subscription != null } } 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 4227d40cf..26282da0d 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/LookAndFeel.kt @@ -21,7 +21,8 @@ import org.tasks.R import org.tasks.Strings.isNullOrEmpty import org.tasks.activities.FilterSelectionActivity import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.dialogs.ColorPalettePicker import org.tasks.dialogs.ColorPalettePicker.Companion.newColorPalette import org.tasks.dialogs.ColorPickerAdapter @@ -242,10 +243,8 @@ class LookAndFeel : InjectingPreferenceFragment() { if (inventory.purchasedThemes() || ThemeBase(index).isFree) { setBaseTheme(index) } else { - startActivityForResult( - Intent(context, PurchaseActivity::class.java), - REQUEST_PURCHASE - ) + newPurchaseDialog(this, REQUEST_PURCHASE) + .show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } } else { setBaseTheme(index) diff --git a/app/src/main/java/org/tasks/preferences/fragments/TaskerListNotification.kt b/app/src/main/java/org/tasks/preferences/fragments/TaskerListNotification.kt index 8dd77fef2..c1fd0c525 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/TaskerListNotification.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/TaskerListNotification.kt @@ -8,7 +8,8 @@ import dagger.hilt.android.AndroidEntryPoint import org.tasks.R import org.tasks.activities.FilterSelectionActivity import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.injection.InjectingPreferenceFragment import org.tasks.locale.bundle.ListNotificationBundle import org.tasks.preferences.DefaultFilterProvider @@ -57,10 +58,8 @@ class TaskerListNotification : InjectingPreferenceFragment() { } if (!inventory.purchasedTasker()) { - startActivityForResult( - Intent(context, PurchaseActivity::class.java), - REQUEST_SUBSCRIPTION - ) + newPurchaseDialog(this, REQUEST_SUBSCRIPTION) + .show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) } } diff --git a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt index 3fd68a8f7..2c70a9f33 100644 --- a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt +++ b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt @@ -24,7 +24,8 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.R -import org.tasks.billing.PurchaseActivity +import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG +import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog import org.tasks.data.TaskDao import org.tasks.dialogs.NewFilterDialog.Companion.newFilterDialog import org.tasks.filters.FilterProvider @@ -83,7 +84,8 @@ class NavigationDrawerFragment : Fragment() { activity?.startActivity(TaskIntents.getTaskListIntent(activity, item)) } else if (item is NavigationDrawerAction) { when (item.requestCode) { - REQUEST_PURCHASE -> startActivity(Intent(context, PurchaseActivity::class.java)) + REQUEST_PURCHASE -> + newPurchaseDialog().show(parentFragmentManager, FRAG_TAG_PURCHASE_DIALOG) REQUEST_DONATE -> startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://tasks.org/donate"))) REQUEST_NEW_FILTER -> newFilterDialog().show(parentFragmentManager, FRAG_TAG_NEW_FILTER) else -> activity?.startActivityForResult(item.intent, item.requestCode) diff --git a/app/src/main/res/layout/activity_purchase.xml b/app/src/main/res/layout/activity_purchase.xml index af9a528a4..1c3be039f 100644 --- a/app/src/main/res/layout/activity_purchase.xml +++ b/app/src/main/res/layout/activity_purchase.xml @@ -1,127 +1,110 @@ - - - - - - + + - - - - - - - - - - - - - - + android:lineSpacingMultiplier="1.2" + android:textSize="16sp" + android:padding="@dimen/keyline_second"/> + - + - + + + - + + + + tools:text="$2.99/year" + app:layout_constraintEnd_toStartOf="@+id/pay_monthly" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_chainStyle="packed" /> + tools:text="$2.99/month" + android:layout_marginStart="@dimen/keyline_first" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/pay_annually" + app:layout_constraintTop_toTopOf="parent" /> + android:text="@string/more_options" + android:textColor="@color/text_secondary" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/pay_annually" + tools:text="@string/back"/> - + - - + + + diff --git a/app/src/main/res/menu/menu_purchase_activity.xml b/app/src/main/res/menu/menu_purchase_activity.xml deleted file mode 100644 index 3b4d83d66..000000000 --- a/app/src/main/res/menu/menu_purchase_activity.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index d13508413..03b06719b 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -450,7 +450,6 @@ O aplikaci Aplikace Tasks je svobodný software s otevřeným zdrojovým kódem licencovaný pod GNU General Public License v3.0 Ikona - Zvýšit, snížit nebo zrušit vaše předplatné Aktuální předplatné Obnovit předplatné Snížit předplatné @@ -493,7 +492,6 @@ Verze %s Neplatný soubor zálohy Nové úkoly na vrchu - Zaplať kolik chceš Měsíčně Ročně Dovolit serveru plánovat opakující se úkoly @@ -591,9 +589,6 @@ Při spuštění Seznamy Přidat filtr - Před zahájení používání bezplatné zkušební verze vyberte níže jakoukoli cenu předplatného. Můžete jej kdykoli zrušit. - Strávil jsem tisíce hodin prací na Tasks a bezplatně zveřejňuji veškerý zdrojový kód online. Za účelem podpory mé práce některé funkce vyžadují předplatné - Ahoj! Jmenuji se Alex. Jsem nezávislý vývojář Tasks Více barev Neplatné uživatelské jméno nebo heslo Synchronizujte své úkoly pomocí aplikace DAVx⁵ diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index fc9085126..6d6aec4dd 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -170,9 +170,6 @@ Boble-stil Tilbage Din støtte betydet meget for mig, tak! - Vælg hvilken som helst abonnementspris herunder for at begynde din gratis prøveperiode. Du kan til enhver tid opsige abonnementet - Jeg har brugt tusindvis af arbejdstimer på Tasks, og jeg udgiver hele kildekoden gratis online. For at støtte mit arbejde kræver nogle funktioner et abonnement - Hej! Jeg hedder Alex. Jeg er den selvstændige udvikler bag Tasks Farvehjul Ugyldigt brugernavn eller kodeord Ringetone, vibrér og mere @@ -205,7 +202,6 @@ Lad serveren planlægge gentagne opgaver Årligt Månedligt - Betal, hvad du vil Nye opgaver øverst Ugyldig sikkerhedskopi-fil Version %s @@ -413,7 +409,6 @@ Nedgrader abonnement Opgrader til pro Opdater køb - Opgrader, nedgrader eller opsig dit abonnement Administrer abonnement hver %1$s i %2$s hver %1$s i %2$s diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7c9865505..ea19973a6 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -471,13 +471,11 @@ Version %s Fehler: %s Symbol - Abonnement hoch-/herabstufen oder kündigen Aktuelles Abonnement Abonnement wiederherstellen Abonnement herabstufen Abonnement hochstufen Abonnement kündigen - Nennen Sie Ihren Preis monatlich jährlich Manuelle Sortierung @@ -528,9 +526,6 @@ Klingelton, Vibration und mehr Ungültiger Benutzername oder Passwort Farbkreis - Hallo! Mein Name ist Alex. Ich bin der unabhängige Entwickler hinter Tasks - Ich habe Tausende von Stunden mit der Arbeit an Tasks verbracht und veröffentliche den gesamten Quellcode kostenlos online. Um meine Arbeit zu unterstützen, erfordern einige Funktionen ein Abonnement - Wählen Sie unten einen beliebigen Abonnementpreis aus, um Ihre kostenlose Testversion zu starten. Sie können jederzeit kündigen Ihre Unterstützung bedeutet mir sehr viel, danke! Zurück Stil der Marken diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 3e7372924..f55c54366 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -471,13 +471,11 @@ Error : %s ", " Icono - Actualizar, rebajar o cancelar su suscripción Suscripción actual Restaurar la suscripción Suscripción de degradación Suscripción de actualización Cancelar la suscripción - Escoger tu precio Mensualmente Anualmente Mi orden @@ -527,9 +525,6 @@ Nombre de usuario o contraseña inválidos El sistema por defecto Rueda de colores - ¡Hola! Me llamo Alex. Soy el desarrollador independiente detrás de Tasks - He pasado miles de horas trabajando en Tareas, y publico todo el código fuente en línea de forma gratuita. Para apoyar mi trabajo, algunas características requieren una suscripción - Elija cualquier precio de suscripción a continuación para iniciar su prueba gratuita. Puede cancelar en cualquier momento Su apoyo significa mucho para mí, ¡gracias! Volver Estilo de chip diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 10a75f451..7df4f4398 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -470,13 +470,11 @@ Baliogabeko babes-kopia fitxategia Zeregin berriak goialdean Ikonoa - Handiagotu, txikiagotu edo ezeztatu zure harpidetza Uneko harpidetza Berrezarri harpidetza Txikiagotu harpidetza Handiagotu harpidetza Ezeztatu harpidetza - Jarri zuk prezioa Hilero Urtero Errorea: %s @@ -527,9 +525,6 @@ Erabiltzaile-izen edo pasahitz okerra Sisteman lehenetsia Kolore-gurpila - Kaixo! Nire izana Alex da. Ni naiz Tasks aplikazioaren garatzaile independentea - Milaka ordu eman ditut Tsks aplikazioan lanean, eta kode guztia argitaratzen dut doan. Nire lana babesteko ezaugarri batzuk harpidetza eskatzen dute - Hautatu azpiko harpidetza salneurri bat zure doako proba hasteko. Nahi duzunean eten dezakezu Zure babesa asko da niretzat, eskerrik asko! Atzera Txip estiloa diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 7d5a3d07f..d21896d0d 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -442,7 +442,6 @@ Anna palvelimen ajoittaa toistuvia tehtäviä Vuosittain Kuukausittain - Nimeä hintasi Uudet tehtävät huipulla Epäsopiva varmuuskopiotiedosto Versio %s @@ -545,7 +544,6 @@ Uusi tehtävä Dashclock-laajennus Päivitä pro versioon - Valitse mikä tahansa alla olevista tilaus vaihtoehdoista aloittaaksesi vapaan kokeilun. Voit keskeyttää milloin haluat Vaatii tilin Etesync.com :ssa tai itsehallinnoidun serverin Ei tärkeyttä Normaali tärkeys @@ -580,8 +578,6 @@ Sulje automaattisesti kun valitaan tehtävä listalta Paikka asetukset Paikat - Olen käyttänyt tuhansia tunteja työskennellen Task ohjelman parissa, ja julkaisen koko lähdekoodin netissä ilmaiseksi. Työni tueksi joidenkin ohjelman ominaisuuksien käyttö vaatii tilauksen - Moi! Nimeni on Alex. Olen itsenäinen ohjelmistontekijä Task ohjelman takana Ongelmien ratkaisu Näytä ilmoitukset puettavassa laitteessasi Puettavan laitteen ilmoitukset @@ -593,7 +589,6 @@ Kirjaudu ulos %s\? Kaikki tälle tilille tallennetut tiedot poistetaan laitteeltasi Alenna tilaustasi Päivitä ostoksesi - Päivitä, alenna tai keskeytä tilauksesi Vain rajoittamattomalla yhteydellä Piilotettu Otsikon alle diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 74e02b039..789fa83dc 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -465,13 +465,11 @@ ", " Version %s Icône - Augmentez, diminuez ou annulez votre abonnement Abonnement actuel Restaurer l\'abonnement Diminuer l\'abonnement Augmenter l\'abonnement Annuler l\'abonnement - Donnez votre prix Chaque mois Chaque année Erreur : %s @@ -522,9 +520,6 @@ Nom d\'utilisateur ou mot de passe invalide Défaut du système Palette de couleurs - Salut ! Je m\'appelle Alex. Je suis le développeur indépendant à l\'origine de Tasks - J\'ai passé des milliers d\'heures à travailler sur Tasks, et je publie gratuitement tout le code source en ligne. Afin de soutenir mon travail, certaines fonctionnalités nécessitent un abonnement - Choisissez l\'un des prix d\'abonnement ci-dessous pour commencer votre essai gratuit. Vous pouvez annuler à tout moment Votre soutien est très important pour moi, merci ! Retour Style de puce diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 5bd6ced29..9bc1311fa 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -468,13 +468,11 @@ %s m ", " Ikon - Előfizetés upgrade-je, downgrade-je vagy lemondása Jelenlegi előfizetés Előfizetés visszaállítása Előfizetés downgrade-je Előfizetés upgrade-je Előfizetés lemondása - Nevezd meg az árat Havi Éves Egyéni sorrend @@ -525,9 +523,6 @@ Hibás felhasználónév vagy jelszó Alapértelmezett Színkör - Szia! Alexnek hívnak. Én vagyok a Tasks mögött álló független fejlesztő - Több ezer órát dolgoztam a Tasks appon, és a teljes forráskódot ingyenesen elérhetővé tettem. A munkám támogatása érdekében néhány funkció eléréséhez előfizetés szükséges - Az ingyenes próbaidőszak megkezdéséhez válassz a lenti előfizetési díjakból. Bármikor lemondhatod az előfizetést A támogatásod sokat jelent nekem, köszönöm! Vissza Jelölő stílusa diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 174d053ba..dd3996c6c 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -358,7 +358,6 @@ Hanya pada koneksi tak terbatas Tingkatkan ke pro Kelola langganan - Tingkatkan, turunkan, atau batalkan langganan anda Segarkan pembelian Langganan Langganan saat ini diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b986bf3d0..ec5a0f911 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -491,9 +491,6 @@ Contornato Indietro Il tuo supporto significa molto per me, grazie! - Scegli, di seguito, un qualunque piano di abbonamento per iniziare la prova gratuita. Puoi annullarla in qualsiasi momento - Ho dedicato a Tasks migliaia di ore di lavoro, pubblicando tutto il codice sorgente online, gratuitamente. Per supportare il mio lavoro alcune funzioni richiedono un abbonamento - Ciao! Mi chiamo Alex. Sono lo sviluppatore, indipendente, di Tasks Cerchio cromatico Nome utente o password non validi Suoneria, vibrazione ed altro @@ -517,12 +514,10 @@ Inserisci il nome dell\'etichetta Inserisci titolo Comprimi attività secondarie - Fai tu il prezzo Licenze di terze parti Questa funzione richiede un abbonamento Annulla abbonamento Ripristina abbonamento - Passa alla versione premium, a quella base o cancella il tuo abbonamento Abbonamento attuale Aiuto & feedback URL diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 6720745d8..ece201d9e 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -500,13 +500,11 @@ משימות חדשות בראש הרשימה ", " סמל - שדרוג, שנמוך או ביטול המינוי מינוי נוכחי שחזור מינוי שנמוך מינוי שדרוג מינוי ביטול מינוי - מה המחיר שלך חודשי שנתי מיקומים @@ -614,9 +612,6 @@ גישה מלאה למסד הנתונים של Tasks איפוס אופן הסידור התמיכה שלך יקרה ללבי, תודה רבה לך! - נא לבחור את מחיר ההרשמה להלן כדי להתחיל בהתנסות חינמית. ניתן לבטל אותה בכל עת - השקעתי אלפי שעות בעבודה על Tasks ואני מפרסם את כל קוד המקור באינטרנט בחינם. כדי לתמוך בעבודה שלי חלק מהתכונות דורשות הרשמה - היי! אני אלכס, המתכנת העצמאי שמאחורי Tasks שם המשתמש או הססמה שגויים צלצול, סוגי רטט ועוד השבתת שיפורי סוללה diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 7090e34ae..c49a27c89 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -465,13 +465,11 @@ URL ", " アイコン - サブスクリプションのアップグレード、ダウングレード、またはキャンセル 現在のサブスクリプション サブスクリプションの復元 サブスクリプションのダウングレード サブスクリプションのアップグレード サブスクリプションのキャンセル - 価格の名前 毎月 毎年 \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 6193fd945..52b63274b 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -467,13 +467,11 @@ 부적합한 백업 파일 새 할일을 가장 위로 아이콘 - 업그레이드, 다운그레이드, 구독 취소 현재 구독 구독 복원 구독 다운그레이드 구독 업그레이드 구독 취소 - 구독 금액 정하기 매월 매년 순서 직접 정렬 @@ -519,7 +517,6 @@ 네비게이션 서랍 위치 설정 위치 - 안녕하세요! Tasks의 1인 개발자 알렉스입니다 다크 테마 사용 시 채도를 낮춥니다 다크 테마 사용 시 채도를 낮추지 않습니다 저채도 색상 @@ -528,9 +525,7 @@ 배경색 채움 칩 스타일 - 저는 Tasks 개발에 엄청나게 많은 시간을 쏟고 있으며, 모든 소스코드를 웹에 무상으로 공개하고 있습니다. 저의 작업을 후원하기 위해 일부 기능은 구독이 필요합니다 당신의 후원은 저에게 큰 힘이 됩니다. 감사합니다! - 무료 체험을 시작하려면 아래에서 구독 금액을 선택하세요. 언제라도 구독을 취소하실 수 있습니다 색상환 유효하지 않은 사용자명과 비밀번호 신호음, 진동 등 diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 8c45ae723..1f40b0e38 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -470,13 +470,11 @@ Ugyldig sikkerhetskopifil Nye gjøremål øverst Ikon - Oppgrader, nedgrader eller avbryt ditt abonnement Nåværende abonnement Gjenopprett abonnement Nedgrader abonnement Oppgrader abonnement Avbryt abonnement - Betal det du vil Månedlig Årlig Feil: %s @@ -576,11 +574,8 @@ Flis Omrisset Flisstil - Jeg har brukt tusenvis av timer på å jobbe med Tasks, og jeg offentliggjør all kildekoden på nettet gratis. For å støtte mitt arbeid krever noen funksjoner et abonnement - Hei, jeg heter Alex. Jeg er den uavhengige utvikleren bak Tasks Krever en konto med en CalDAV-tjenestetilbyder, eller en selvdrevet tjener. Finn en tjenestetilbyder ved å besøke tasks.org/caldav Fylt - Velg en vilkårlig pris nedenfor for å starte din gratisperiode. Du kan avbryte når som helst. Vis merknader på din ikledbare Ikledbare merknader Boolsk logikkboks 4 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 676ac1b9d..b971d477c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -460,13 +460,11 @@ Filters Filter Accent - Aanmelden, afmelden of annuleer je aanmelding Huidige abonnement Abonnement herstellen Terugdraaien abonnement Abonnement upgraden Abonnement annuleren - Bepaal je prijs Maandelijks Jaarlijks Later @@ -522,9 +520,6 @@ Ongeldige gebruikersnaam of wachtwoord Systeeminstelling Kleurenwiel - Hoi! Mijn naam is Alex. Ik ben de onafhankelijke ontwikkelaar achter Tasks. - Ik heb duizenden uren aan Tasks gewerkt, en ik publiceer de volledige broncode gratis online. Om mijn werk te steunen vereisen sommige functies een abonnement. - Kies hierbeneden een abonnementsprijs om je gratis proefperiode te starten. Je kunt het altijd annuleren. Je steun betekent veel voor me, bedankt! Terug Fiche-stijl diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e4a0983cf..b04e2d0ac 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -481,13 +481,11 @@ Nieprawidłowy plik kopii zapasowej Nowe zadania na górze Ikona - Podwyższyć, obniżyć poziom albo anulować subskrypcję Aktualna subskrypcja Przywróć subskrypcję Obniżyć poziom subskrypcji Podwyższyć poziom subskrypcji Anuluj subskrypcję - Nazwij swoją cenę Miesięczne Rocznie Ręczne @@ -538,9 +536,6 @@ Nieprawidłowa nazwa użytkownika lub hasło Domyślny systemowy Paleta - Cześć! Mam na imię Alex. Jestem niezależnym deweloperem stojącym za Tasks - Spędziłem tysiące godzin pracując nad Tasks i publikuję cały kod źródłowy online za darmo. Aby wesprzeć moją pracę, niektóre funkcję wymagają subskrypcji - Wybierz dowolną cenę subskrypcji poniżej, aby rozpocząć bezpłatny okres próbny. Możesz zrezygnować w każdej chwili Twoje wsparcie wiele dla mnie znaczy, dziękuję! Wstecz Styl chipa diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 4f9b10960..7c5c8cdc3 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -490,9 +490,6 @@ Estilo de notificação Voltar Seu suporte significa muito para mim, obrigado! - Escolha qualquer preço de subscrição abaixo para começar seu teste grátis. Você poderá cancelar a qualquer momento - Eu investi centenas de horas trabalhando no Tasks, e eu publico todo o código fonte online de graça. Para apoiar meu trabalho, algumas funcionalidades precisam de um plano de subscrição - Olá! Meu nome é Alex e eu sou o desenvolvedor independente por trás do Tasks Roda de cores Nome de usuário ou senha inválido Toque, vibrações e mais @@ -526,7 +523,6 @@ Permita que o servidor agende tarefas recorrentes Anualmente Mensalmente - Dê seu valor Novas tarefas ao topo Arquivo de restauro inválido Versão %s @@ -539,7 +535,6 @@ Rebaixar plano Recuperar plano Plano atual - Atualizar, rebaixar ou cancelar o seu plano Ajuda e Comentários ", " Erro: %s diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index bfcee6eb8..a368dcfe7 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -553,9 +553,6 @@ Estilo de notificação Voltar Seu suporte significa muito para mim, obrigado! - Escolha qualquer preço de assinatura abaixo para começar seu teste grátis. Poderá cancelar a qualquer momento - Eu investi centenas de horas a trabalhar no Tasks e publico todo o código-fonte online de graça. Para apoiar meu trabalho, algumas funcionalidades precisam de uma assinatura - Olá! O meu nome é Alex e sou o programador independente por trás do Tasks Roda de cores Predefinição do Sistema Nome de utilizador ou palavra-passe inválido @@ -602,10 +599,8 @@ Temporareamente mostrar tarefas quando completas Permita que o servidor agende tarefas recorrentes Minha ordem - Dê o seu valor Atualizar assinatura Rebaixar assinatura - Atualizar, rebaixar ou cancelar a sua assinatura Não foi possível conectar %s m Sincronize a suas tarefas com a app DAVx⁵ diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e6e5df856..f3ea4dec3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -482,12 +482,10 @@ Текущая подписка Восстановить подписку Отменить подписку - Назовите свою цену URL Ошибка: %s ", " Генерация уведомлений - Повысить, понизить уровень подписки или отменить ее Понизить уровень подписки Повысить уровень подписки Ручная сортировка @@ -543,9 +541,6 @@ Неверное имя пользователя или пароль Системная по умолчанию Палитра - Привет! Меня зовут Алекс. Я - независимый разработчик, стоящий за программой Tasks - Я потратил тысячи часов, работая над Tasks, и я публикую весь исходный код онлайн, бесплатно. Для того, чтобы поддержать мою работу, некоторые функциональности требуют подписки - Выберите любую сумму подписки для того, чтобы начать Ваш бесплатный пробный период. Вы можете отказаться в любой момент Ваша поддержка много значит для меня, спасибо! Назад Стиль индикаторов списков diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index f880e674a..28746fe67 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -465,13 +465,11 @@ Ogiltig säkerhetskopia Nya uppgifter överst Ikon - Uppgradera, nedgradera eller Avbryt prenumerationen Hantera prenumerationer Återställ prenumeration Nedgradera prenumeration Uppgradera prenumerationen Avbryt prenumeration - Namnge ditt pris Månadsvis Årligen Min ordning diff --git a/app/src/main/res/values-sw384dp/bools.xml b/app/src/main/res/values-sw384dp/bools.xml new file mode 100644 index 000000000..78e6eef0e --- /dev/null +++ b/app/src/main/res/values-sw384dp/bools.xml @@ -0,0 +1,4 @@ + + + false + \ No newline at end of file diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index bd342456f..fdcbd1909 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -243,9 +243,6 @@ கோடிட்டுக் காட்டப்பட்டுள்ளது சிப் பாணி மீண்டும் - உங்கள் இலவச சோதனையைத் தொடங்க கீழே உள்ள எந்த சந்தா விலையையும் தேர்வு செய்யவும். நீங்கள் எந்த நேரத்திலும் ரத்து செய்யலாம் - நான் பணிகளில் ஆயிரக்கணக்கான மணிநேரங்களை செலவிட்டேன், மேலும் மூலக் குறியீடு அனைத்தையும் ஆன்லைனில் இலவசமாக வெளியிடுகிறேன். எனது பணியை ஆதரிக்க சில அம்சங்களுக்கு சந்தா தேவை - வணக்கம்! என் பெயர் அலெக்ஸ். பணிகளுக்குப் பின்னால் உள்ள சுயாதீன டெவலப்பர் நான் வண்ண சக்கரம் தவறான பயனர்பெயர் அல்லது கடவுச்சொல் ரிங்டோன், அதிர்வுகள் மற்றும் பல @@ -278,7 +275,6 @@ தொடர்ச்சியான பணிகளை சேவையாக அட்டவணைப்படுத்தட்டும் ஆண்டு மாதாந்திர - உங்கள் விலைக்கு பெயரிடுங்கள் மேலே புதிய பணிகள் தவறான காப்பு கோப்பு பதிப்பு %s @@ -321,7 +317,6 @@ தற்போதைய சந்தா பதிவு வாங்குதல்களைப் புதுப்பிக்கவும் - உங்கள் சந்தாவை மேம்படுத்தவும், தரமிறக்கவும் அல்லது ரத்து செய்யவும் சந்தாவை நிர்வகிக்கவும் சார்புக்கு மேம்படுத்தவும் அளவிடப்படாத இணைப்புகளில் மட்டுமே diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ba01e0649..0f7d3a893 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -471,13 +471,11 @@ Hata: %s ", " Simge - Aboneliğinizi yükseltin, alçaltın veya iptal edin Geçerli abonelik Aboneliği geri getir Aboneliği alçalt Aboneliği yükselt Aboneliği iptal et - Fiyat belirleyin Aylık Yıllık Düzenim @@ -527,9 +525,6 @@ Geçersiz kullanıcı adı veya parola Sistem öntanımlısı Renk tekeri - Hey! Ben Alex. Tasks\'ın arkasındaki bağımsız geliştiriciyim - Binlerce saatimi Tasks\'ta çalışarak geçirdim, kaynak kodun tümünü çevrim içi olarak ücretsiz yayımladım. Çalışmamı desteklemek için bazı özellikler abonelik gerektirir - Ücretsiz denemenizi başlatmak için aşağıdan herhangi abonelik bedelini seçin. İstediğinizde iptal edebilirsiniz Desteğiniz çok şey ifade ediyor, teşekkürler! Geri Yonga biçimi diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 4193167e1..260fe7e94 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -508,7 +508,6 @@ Google Tasks Відновити підписку Поточна підписка - Змініть або скасуйте підписку Підтвердіть пароль шифрування Пароль шифрування Потрібний пароль шифрування @@ -532,7 +531,6 @@ Згорнути підзавдання Розгорнути підзавдання Дозволити серверу встановлювати регулярні завдання - Назвіть свою ціну Щорічно Щомісячно Ця функція потребує підписки @@ -562,9 +560,6 @@ Стиль індикаторів списків Назад Ваша підтримка багато означає для мене. Дякую! - Оберіть будь-яку вартість підписки знизу, щоб розпочати безоплатний пробний період. Його можна скасувати будь-коли - Я витратив тисячі годин, працюючи над Tasks, і я публікую весь код онлайн безоплатно. Щоб підтримати мою роботу, деякі функції потребують підписки - Привіт! Моє ім\'я Алекс. Я - незалежний розробник Tasks Палітра Невірне ім\'я користувача або пароль Мелодія, вібрація та інше diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c8fee8678..9c1643216 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -460,13 +460,11 @@ 无效的备份文件 新任务显示在顶部 图标 - 升级,降级或取消您的订阅 当前订阅 恢复订阅 降级订阅 升级订阅 取消订阅 - 您愿意支付多少费用 每月 每年 ", " @@ -518,9 +516,6 @@ 无效的用户名或密码 系统默认 给滚轮着色 - 你好!我叫Alex,是Tasks背后的独立开发者 - 我已经花了数千个小时用于开发Tasks,并且在网上免费发布了所有源代码。 为了支持我的工作,某些功能需要订阅 - 选择下方任意订阅价格即可开始免费试用。 你可以随时取消 您的支持对我很重要,谢谢! 返回 流式布局样式 diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml index 94074fd18..ab08ecd63 100644 --- a/app/src/main/res/values/bools.xml +++ b/app/src/main/res/values/bools.xml @@ -4,4 +4,5 @@ false false false + true \ No newline at end of file diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 15b7da07f..9272ab9a8 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -7,6 +7,7 @@ org.tasks org.tasks.opentasks AEdPqrEAAAAI49v5bBusi_bq1bgLBB1LIsepNV0eBrFkQrBZkw + 1006257750459-3jt0e32kbqgug7hkluqe26d5mbno92no.apps.googleusercontent.com @string/ok @string/cancel Tasks Shortcut @@ -17,6 +18,27 @@ https://api.etesync.com https://tasks.org/sync + + Subscribe to unlock additional features and support open source software! + Sync with Tasks.org + No platform lock-in + Tasks.org is based on open internet standards + You are the customer + Tasks.org does not monetize you or your data + Many new features coming soon! + Sync with third-party or self-hosted servers + End-to-end encryption with EteSync + Multiple Google Task accounts + Additional features + Unlock all themes, colors, and icons + Improved location search with Google Places + Tasker plugins + New subscribers receive a 7-day free trial + Upgrade or downgrade at any time + Your remaining balance will apply to your new subscription + Cancel at any time + benefits are retained until the end of your billing period + date_shortcut_morning date_shortcut_afternoon date_shortcut_evening diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2fa8493ed..f57656be8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -489,8 +489,7 @@ File %1$s contained %2$s.\n\n Could not connect Only on unmetered connections Upgrade to pro - Manage subscription - Upgrade, downgrade, or cancel your subscription + Modify subscription Refresh purchases Subscribe Current subscription @@ -534,7 +533,7 @@ File %1$s contained %2$s.\n\n Version %s Invalid backup file New tasks on top - Name your price + More options Monthly Yearly Let server schedule recurring tasks @@ -569,9 +568,6 @@ File %1$s contained %2$s.\n\n Ringtone, vibrations, and more Invalid username or password Color wheel - Hi! My name is Alex. I am the independent developer behind Tasks - I have spent thousands of hours working on Tasks, and I publish all of the source code online for free. In order to support my work some features require a subscription - Choose any subscription price below to start your free trial. You may cancel at any time Your support means a lot to me, thank you! Back Chip style @@ -658,4 +654,8 @@ File %1$s contained %2$s.\n\n Delete this comment? Has subtasks Is subtask + $%s/year + $%s/yr + $%s/month + $%s/mo diff --git a/app/src/main/res/xml/help_and_feedback.xml b/app/src/main/res/xml/help_and_feedback.xml index 0fa878cb9..af3ce7da8 100644 --- a/app/src/main/res/xml/help_and_feedback.xml +++ b/app/src/main/res/xml/help_and_feedback.xml @@ -51,11 +51,11 @@ android:key="@string/upgrade_to_pro" android:title="@string/upgrade_to_pro" app:allowDividerAbove="true" - app:icon="@drawable/ic_outline_attach_money_24px"> - - + app:icon="@drawable/ic_outline_attach_money_24px" /> + +