mirror of https://github.com/tasks/tasks
New purchase activity
parent
505ad779f2
commit
dc8f722589
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string-array name="pro_description">
|
|
||||||
<item>@string/themes</item>
|
|
||||||
<item>@string/pro_caldav_sync</item>
|
|
||||||
<item>@string/pro_multiple_google_task_accounts</item>
|
|
||||||
<item>@string/pro_tasker_plugins</item>
|
|
||||||
<item>@string/pro_dashclock_extension</item>
|
|
||||||
</string-array>
|
|
||||||
</resources>
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string-array name="pro_description"/>
|
|
||||||
</resources>
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string-array name="pro_description">
|
|
||||||
<item>@string/themes</item>
|
|
||||||
<item>@string/pro_caldav_sync</item>
|
|
||||||
<item>@string/pro_etesync</item>
|
|
||||||
<item>@string/pro_multiple_google_task_accounts</item>
|
|
||||||
<item>@string/pro_google_places_search</item>
|
|
||||||
<item>@string/pro_tasker_plugins</item>
|
|
||||||
<item>@string/pro_dashclock_extension</item>
|
|
||||||
</string-array>
|
|
||||||
</resources>
|
|
||||||
@ -1,261 +0,0 @@
|
|||||||
package org.tasks.billing;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnDismissListener;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
|
||||||
import com.google.android.material.button.MaterialButtonToggleGroup;
|
|
||||||
import com.google.common.collect.ContiguousSet;
|
|
||||||
import com.google.common.collect.DiscreteDomain;
|
|
||||||
import com.google.common.collect.Range;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.LocalBroadcastManager;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.dialogs.IconLayoutManager;
|
|
||||||
import org.tasks.injection.DialogFragmentComponent;
|
|
||||||
import org.tasks.injection.ForActivity;
|
|
||||||
import org.tasks.injection.InjectingDialogFragment;
|
|
||||||
import org.tasks.locale.Locale;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
|
|
||||||
public class NameYourPriceDialog extends InjectingDialogFragment implements OnPurchasesUpdated {
|
|
||||||
|
|
||||||
private static final String EXTRA_MONTHLY = "extra_monthly";
|
|
||||||
private static final String EXTRA_PRICE = "extra_price";
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject @ForActivity Context context;
|
|
||||||
@Inject BillingClient billingClient;
|
|
||||||
@Inject LocalBroadcastManager localBroadcastManager;
|
|
||||||
@Inject Inventory inventory;
|
|
||||||
@Inject Locale locale;
|
|
||||||
@Inject Theme theme;
|
|
||||||
|
|
||||||
@BindView(R.id.recycler_view)
|
|
||||||
RecyclerView recyclerView;
|
|
||||||
|
|
||||||
@BindView(R.id.screen_wait)
|
|
||||||
View loadingView;
|
|
||||||
|
|
||||||
@BindView(R.id.buttons)
|
|
||||||
MaterialButtonToggleGroup buttons;
|
|
||||||
|
|
||||||
@BindView(R.id.subscribe)
|
|
||||||
MaterialButton subscribe;
|
|
||||||
|
|
||||||
@BindView(R.id.unsubscribe)
|
|
||||||
MaterialButton unsubscribe;
|
|
||||||
|
|
||||||
private PurchaseAdapter adapter;
|
|
||||||
private Purchase currentSubscription = null;
|
|
||||||
private BroadcastReceiver purchaseReceiver =
|
|
||||||
new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private OnDismissListener listener;
|
|
||||||
|
|
||||||
static NameYourPriceDialog newNameYourPriceDialog() {
|
|
||||||
return new NameYourPriceDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
|
||||||
View view = theme.getLayoutInflater(context).inflate(R.layout.dialog_name_your_price, null);
|
|
||||||
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
|
|
||||||
setWaitScreen(true);
|
|
||||||
|
|
||||||
adapter = new PurchaseAdapter(context, theme, locale, this::onPriceChanged);
|
|
||||||
|
|
||||||
buttons.addOnButtonCheckedListener(this::onButtonChecked);
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
buttons.check(
|
|
||||||
savedInstanceState.getBoolean(EXTRA_MONTHLY)
|
|
||||||
? R.id.button_monthly
|
|
||||||
: R.id.button_annually);
|
|
||||||
adapter.setSelected(savedInstanceState.getInt(EXTRA_PRICE));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialogBuilder.newDialog(R.string.name_your_price).setView(view).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onButtonChecked(MaterialButtonToggleGroup group, int id, boolean checked) {
|
|
||||||
if (id == R.id.button_monthly) {
|
|
||||||
if (!checked && group.getCheckedButtonId() != R.id.button_annually) {
|
|
||||||
group.check(R.id.button_monthly);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!checked && group.getCheckedButtonId() != R.id.button_monthly) {
|
|
||||||
group.check(R.id.button_annually);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateSubscribeButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMonthly() {
|
|
||||||
return buttons.getCheckedButtonId() == R.id.button_monthly;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
|
|
||||||
outState.putBoolean(EXTRA_MONTHLY, isMonthly());
|
|
||||||
outState.putInt(EXTRA_PRICE, adapter.getSelected());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
@OnClick(R.id.subscribe)
|
|
||||||
protected void subscribe() {
|
|
||||||
if (currentSubscriptionSelected() && currentSubscription.isCanceled()) {
|
|
||||||
billingClient.initiatePurchaseFlow(
|
|
||||||
(Activity) context, currentSubscription.getSku(), SkuDetails.TYPE_SUBS, null);
|
|
||||||
} else {
|
|
||||||
billingClient.initiatePurchaseFlow(
|
|
||||||
(Activity) context,
|
|
||||||
String.format("%s_%02d", isMonthly() ? "monthly" : "annual", adapter.getSelected()),
|
|
||||||
SkuDetails.TYPE_SUBS,
|
|
||||||
currentSubscription == null ? null : currentSubscription.getSku());
|
|
||||||
}
|
|
||||||
billingClient.addPurchaseCallback(this);
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setup() {
|
|
||||||
currentSubscription = inventory.getSubscription();
|
|
||||||
if (adapter.getSelected() == 0) {
|
|
||||||
if (currentSubscription == null) {
|
|
||||||
adapter.setSelected(1);
|
|
||||||
} else {
|
|
||||||
adapter.setSelected(currentSubscription.getSubscriptionPrice());
|
|
||||||
buttons.check(currentSubscription.isMonthly() ? R.id.button_monthly : R.id.button_annually);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsubscribe.setVisibility(
|
|
||||||
currentSubscription == null || currentSubscription.isCanceled() ? View.GONE : View.VISIBLE);
|
|
||||||
updateSubscribeButton();
|
|
||||||
setWaitScreen(false);
|
|
||||||
adapter.submitList(
|
|
||||||
newArrayList(ContiguousSet.create(Range.closed(1, 10), DiscreteDomain.integers())));
|
|
||||||
recyclerView.setLayoutManager(new IconLayoutManager(context));
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.unsubscribe)
|
|
||||||
protected void manageSubscription() {
|
|
||||||
startActivity(
|
|
||||||
new Intent(
|
|
||||||
Intent.ACTION_VIEW,
|
|
||||||
Uri.parse(getString(R.string.manage_subscription_url, currentSubscription.getSku()))));
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onPriceChanged(Integer price) {
|
|
||||||
adapter.setSelected(price);
|
|
||||||
updateSubscribeButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSubscribeButton() {
|
|
||||||
subscribe.setEnabled(true);
|
|
||||||
if (currentSubscription == null) {
|
|
||||||
subscribe.setText(R.string.button_subscribe);
|
|
||||||
} else if (currentSubscriptionSelected()) {
|
|
||||||
if (currentSubscription.isCanceled()) {
|
|
||||||
subscribe.setText(R.string.button_restore_subscription);
|
|
||||||
} else {
|
|
||||||
subscribe.setText(R.string.button_current_subscription);
|
|
||||||
subscribe.setEnabled(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
subscribe.setText(isUpgrade() ? R.string.button_upgrade : R.string.button_downgrade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isUpgrade() {
|
|
||||||
return isMonthly() == currentSubscription.isMonthly()
|
|
||||||
? currentSubscription.getSubscriptionPrice() < adapter.getSelected()
|
|
||||||
: isMonthly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean currentSubscriptionSelected() {
|
|
||||||
return currentSubscription != null
|
|
||||||
&& isMonthly() == currentSubscription.isMonthly()
|
|
||||||
&& adapter.getSelected() == currentSubscription.getSubscriptionPrice();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(DialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setWaitScreen(boolean isWaitScreen) {
|
|
||||||
recyclerView.setVisibility(isWaitScreen ? View.GONE : View.VISIBLE);
|
|
||||||
buttons.setVisibility(isWaitScreen ? View.GONE : View.VISIBLE);
|
|
||||||
subscribe.setVisibility(isWaitScreen ? View.GONE : View.VISIBLE);
|
|
||||||
loadingView.setVisibility(isWaitScreen ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
localBroadcastManager.registerPurchaseReceiver(purchaseReceiver);
|
|
||||||
billingClient.queryPurchases();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
|
|
||||||
localBroadcastManager.unregisterReceiver(purchaseReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
NameYourPriceDialog setOnDismissListener(OnDismissListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
|
||||||
super.onDismiss(dialog);
|
|
||||||
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onDismiss(dialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPurchasesUpdated() {
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.button_more_info)
|
|
||||||
public void openDocumentation() {
|
|
||||||
startActivity(
|
|
||||||
new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.subscription_help_url))));
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
package org.tasks.billing;
|
package org.tasks.billing;
|
||||||
|
|
||||||
public interface OnPurchasesUpdated {
|
public interface OnPurchasesUpdated {
|
||||||
void onPurchasesUpdated();
|
void onPurchasesUpdated(boolean success);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
package org.tasks.billing;
|
|
||||||
|
|
||||||
import static org.tasks.billing.PurchaseDialog.newPurchaseDialog;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.injection.ActivityComponent;
|
|
||||||
import org.tasks.injection.InjectingAppCompatActivity;
|
|
||||||
import org.tasks.themes.ThemeAccent;
|
|
||||||
|
|
||||||
public class PurchaseActivity extends InjectingAppCompatActivity {
|
|
||||||
|
|
||||||
private static final String FRAG_TAG_PURCHASE = "frag_tag_purchase";
|
|
||||||
|
|
||||||
@Inject Inventory inventory;
|
|
||||||
@Inject ThemeAccent themeAccent;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
themeAccent.applyStyle(getTheme());
|
|
||||||
|
|
||||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
|
||||||
PurchaseDialog dialog = (PurchaseDialog) fragmentManager.findFragmentByTag(FRAG_TAG_PURCHASE);
|
|
||||||
if (dialog == null) {
|
|
||||||
dialog = newPurchaseDialog();
|
|
||||||
dialog.show(fragmentManager, FRAG_TAG_PURCHASE);
|
|
||||||
}
|
|
||||||
dialog.setOnDismissListener(d -> finish());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inject(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,215 @@
|
|||||||
|
package org.tasks.billing
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import butterknife.ButterKnife
|
||||||
|
import butterknife.OnClick
|
||||||
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
import com.google.common.collect.ContiguousSet
|
||||||
|
import com.google.common.collect.DiscreteDomain
|
||||||
|
import com.google.common.collect.Lists
|
||||||
|
import com.google.common.collect.Range
|
||||||
|
import org.tasks.LocalBroadcastManager
|
||||||
|
import org.tasks.R
|
||||||
|
import org.tasks.databinding.ActivityPurchaseBinding
|
||||||
|
import org.tasks.dialogs.DialogBuilder
|
||||||
|
import org.tasks.dialogs.IconLayoutManager
|
||||||
|
import org.tasks.injection.ActivityComponent
|
||||||
|
import org.tasks.injection.ThemedInjectingAppCompatActivity
|
||||||
|
import org.tasks.locale.Locale
|
||||||
|
import org.tasks.themes.Theme
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.lang.String
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val EXTRA_MONTHLY = "extra_monthly"
|
||||||
|
private const val EXTRA_PRICE = "extra_price"
|
||||||
|
|
||||||
|
class PurchaseActivity : ThemedInjectingAppCompatActivity(), OnPurchasesUpdated, Toolbar.OnMenuItemClickListener {
|
||||||
|
|
||||||
|
@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
|
||||||
|
@Inject lateinit var theme: Theme
|
||||||
|
|
||||||
|
private lateinit var binding: ActivityPurchaseBinding
|
||||||
|
private lateinit var adapter: PurchaseAdapter
|
||||||
|
|
||||||
|
private var currentSubscription: Purchase? = null
|
||||||
|
|
||||||
|
private val purchaseReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
setup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityPurchaseBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
ButterKnife.bind(this)
|
||||||
|
|
||||||
|
adapter = PurchaseAdapter(this, theme, locale, ::onPriceChanged)
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
binding.buttons.check(
|
||||||
|
if (savedInstanceState.getBoolean(EXTRA_MONTHLY)) R.id.button_monthly else R.id.button_annually)
|
||||||
|
adapter.selected = savedInstanceState.getInt(EXTRA_PRICE)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.buttons.addOnButtonCheckedListener { group: MaterialButtonToggleGroup?, id: Int, checked: Boolean -> 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, SkuDetails.TYPE_SUBS, null)
|
||||||
|
} else {
|
||||||
|
billingClient.initiatePurchaseFlow(this, String.format("%s_%02d", if (isMonthly()) "monthly" else "annual", adapter.selected),
|
||||||
|
SkuDetails.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inject(component: ActivityComponent) {
|
||||||
|
component.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
Lists.newArrayList(ContiguousSet.create(Range.closed(1, 10), DiscreteDomain.integers())))
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,77 +0,0 @@
|
|||||||
package org.tasks.billing;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Lists.transform;
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static org.tasks.billing.NameYourPriceDialog.newNameYourPriceDialog;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnDismissListener;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import org.tasks.R;
|
|
||||||
import org.tasks.dialogs.DialogBuilder;
|
|
||||||
import org.tasks.injection.DialogFragmentComponent;
|
|
||||||
import org.tasks.injection.ForActivity;
|
|
||||||
import org.tasks.injection.InjectingDialogFragment;
|
|
||||||
import org.tasks.themes.Theme;
|
|
||||||
|
|
||||||
public class PurchaseDialog extends InjectingDialogFragment {
|
|
||||||
|
|
||||||
private static final String FRAG_TAG_PRICE = "frag_tag_price";
|
|
||||||
|
|
||||||
@Inject DialogBuilder dialogBuilder;
|
|
||||||
@Inject Theme theme;
|
|
||||||
@Inject @ForActivity Context context;
|
|
||||||
private OnDismissListener listener;
|
|
||||||
|
|
||||||
public static PurchaseDialog newPurchaseDialog() {
|
|
||||||
return new PurchaseDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
|
||||||
View view = theme.getLayoutInflater(context).inflate(R.layout.dialog_purchase, null);
|
|
||||||
TextView textView = view.findViewById(R.id.feature_list);
|
|
||||||
String[] rows = context.getResources().getStringArray(R.array.pro_description);
|
|
||||||
textView.setText(Joiner.on('\n').join(transform(asList(rows), item -> "\u2022 " + item)));
|
|
||||||
return dialogBuilder
|
|
||||||
.newDialog(R.string.pro_support_development)
|
|
||||||
.setView(view)
|
|
||||||
.setPositiveButton(
|
|
||||||
R.string.name_your_price,
|
|
||||||
(dialog, which) -> {
|
|
||||||
newNameYourPriceDialog()
|
|
||||||
.setOnDismissListener(listener)
|
|
||||||
.show(getFragmentManager(), FRAG_TAG_PRICE);
|
|
||||||
listener = null;
|
|
||||||
dialog.dismiss();
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOnDismissListener(OnDismissListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
|
||||||
super.onDismiss(dialog);
|
|
||||||
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onDismiss(dialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(DialogFragmentComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="?attr/colorAccent" android:state_checked="true"/>
|
<item android:color="?attr/colorAccent" android:state_enabled="true"/>
|
||||||
<item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_checked="false"/>
|
<item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_enabled="false"/>
|
||||||
</selector>
|
</selector>
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:color="?attr/colorAccent" android:state_checked="true"/>
|
||||||
|
<item android:alpha="0.12" android:color="?attr/colorOnSurface" android:state_checked="false"/>
|
||||||
|
</selector>
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
layout="@layout/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/upgrade_blurb_1"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/upgrade_blurb_2"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/upgrade_blurb_3"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:text="@string/upgrade_blurb_4"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/screen_wait"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
android:id="@+id/buttons"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:checkedButton="@id/button_monthly"
|
||||||
|
app:singleSelection="true"
|
||||||
|
android:paddingLeft="@dimen/keyline_content_inset"
|
||||||
|
android:paddingStart="@dimen/keyline_content_inset"
|
||||||
|
android:paddingEnd="@dimen/keyline_content_inset"
|
||||||
|
android:paddingRight="@dimen/keyline_content_inset">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/button_monthly"
|
||||||
|
style="@style/OutlineButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/monthly" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/button_annually"
|
||||||
|
style="@style/OutlineButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/annually" />
|
||||||
|
|
||||||
|
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:paddingLeft="@dimen/keyline_content_inset"
|
||||||
|
android:paddingStart="@dimen/keyline_content_inset"
|
||||||
|
android:paddingEnd="@dimen/keyline_content_inset"
|
||||||
|
android:paddingRight="@dimen/keyline_content_inset" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/subscribe"
|
||||||
|
style="@style/OutlineButton"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_margin="@dimen/keyline_first"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:strokeColor="@color/button_accent_stroke"
|
||||||
|
android:text="@string/button_subscribe" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/unsubscribe"
|
||||||
|
style="@style/OutlineButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/keyline_first"
|
||||||
|
android:padding="@dimen/keyline_first"
|
||||||
|
app:strokeColor="?attr/colorSecondary"
|
||||||
|
android:text="@string/button_unsubscribe"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@ -1,83 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/keyline_first"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/screen_wait"
|
|
||||||
style="?android:attr/progressBarStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:indeterminate="true"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
|
||||||
android:id="@+id/buttons"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:checkedButton="@id/button_monthly"
|
|
||||||
app:singleSelection="true">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/button_monthly"
|
|
||||||
style="@style/OutlineButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/monthly"/>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/button_annually"
|
|
||||||
style="@style/OutlineButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/annually"/>
|
|
||||||
|
|
||||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/recycler_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"/>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/subscribe"
|
|
||||||
style="@style/TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:text="@string/button_subscribe"/>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/unsubscribe"
|
|
||||||
style="@style/TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:text="@string/button_unsubscribe"
|
|
||||||
android:visibility="gone"/>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/button_more_info"
|
|
||||||
style="@style/TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:text="@string/button_more_info"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/keyline_first"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/pro_description"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingTop="@dimen/keyline_first"
|
|
||||||
android:text="@string/pro_subscribe_now"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/feature_list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tasks="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_more_info"
|
||||||
|
android:title="@string/button_more_info"
|
||||||
|
android:icon="@drawable/ic_outline_help_outline_24px"
|
||||||
|
android:contentDescription="@string/button_more_info"
|
||||||
|
tasks:showAsAction="ifRoom" />
|
||||||
|
</menu>
|
||||||
Loading…
Reference in New Issue