From c66d5601e9d7c92e604941c647062695f445616d Mon Sep 17 00:00:00 2001 From: Dima-1 Date: Wed, 22 Apr 2020 22:04:00 +0300 Subject: [PATCH] Discount badge on Choose plan --- .../purchase_dialog_outline_btn_bg_dark.xml | 8 ++ .../purchase_dialog_outline_btn_bg_light.xml | 8 ++ .../layout/purchase_dialog_card_button_ex.xml | 87 +++++++------- .../res/layout/purchase_dialog_fragment.xml | 55 ++++++--- .../layout/purchase_dialog_osm_live_card.xml | 5 +- OsmAnd/res/values-id/strings.xml | 2 +- OsmAnd/res/values/attrs.xml | 1 + OsmAnd/res/values/colors.xml | 3 +- OsmAnd/res/values/strings.xml | 4 +- OsmAnd/res/values/styles.xml | 2 + .../chooseplan/ChoosePlanDialogFragment.java | 106 ++++++++++++------ .../net/osmand/plus/inapp/InAppPurchases.java | 56 +++++++-- 12 files changed, 223 insertions(+), 114 deletions(-) create mode 100644 OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_dark.xml create mode 100644 OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_light.xml diff --git a/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_dark.xml b/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_dark.xml new file mode 100644 index 0000000000..3a35b91f36 --- /dev/null +++ b/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_dark.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_light.xml b/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_light.xml new file mode 100644 index 0000000000..8116459637 --- /dev/null +++ b/OsmAnd/res/drawable/purchase_dialog_outline_btn_bg_light.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/OsmAnd/res/layout/purchase_dialog_card_button_ex.xml b/OsmAnd/res/layout/purchase_dialog_card_button_ex.xml index 726c6f11ee..2d261055dd 100644 --- a/OsmAnd/res/layout/purchase_dialog_card_button_ex.xml +++ b/OsmAnd/res/layout/purchase_dialog_card_button_ex.xml @@ -16,10 +16,10 @@ android:layout_height="wrap_content" android:baselineAligned="false" android:orientation="vertical" - android:paddingLeft="@dimen/card_padding" - android:paddingRight="@dimen/card_padding" - android:paddingEnd="@dimen/card_padding" - android:paddingStart="@dimen/card_padding"> + android:paddingLeft="@dimen/list_content_padding" + android:paddingRight="@dimen/list_content_padding" + android:paddingEnd="@dimen/list_content_padding" + android:paddingStart="@dimen/list_content_padding"> - - - - - - - - + android:layout_height="match_parent"> + android:layout_weight="1" + android:layout_gravity="center" + android:textColor="?attr/dialog_text_description_color" + android:textSize="@dimen/default_desc_text_size" + osmand:typeface="@string/font_roboto_regular" + tools:text="$0.62 / month" /> + + + + - diff --git a/OsmAnd/res/layout/purchase_dialog_fragment.xml b/OsmAnd/res/layout/purchase_dialog_fragment.xml index 17466ed5b7..db87e7d0c6 100644 --- a/OsmAnd/res/layout/purchase_dialog_fragment.xml +++ b/OsmAnd/res/layout/purchase_dialog_fragment.xml @@ -1,6 +1,5 @@ - + android:tint="@color/icon_color_default_light" /> + android:layout_marginStart="@dimen/list_header_padding" /> @@ -54,8 +53,8 @@ android:layout_marginLeft="@dimen/list_content_padding_large" android:layout_marginRight="@dimen/list_content_padding_large" android:orientation="vertical" - android:layout_marginStart="@dimen/list_content_padding_large" - android:layout_marginEnd="@dimen/list_content_padding_large"> + android:layout_marginStart="@dimen/list_content_padding_large" + android:layout_marginEnd="@dimen/list_content_padding_large"> + tools:text="@string/purchase_dialog_travel_description" /> - + android:orientation="vertical" /> + + + + + + + android:layout_marginEnd="@dimen/card_padding" + android:layout_marginStart="@dimen/card_padding"> + android:paddingStart="@dimen/list_content_padding" + android:paddingEnd="@dimen/list_content_padding" /> + android:layout_marginEnd="@dimen/card_padding" + android:layout_marginStart="@dimen/card_padding"> + android:paddingStart="@dimen/list_content_padding" + android:paddingEnd="@dimen/list_content_padding" /> diff --git a/OsmAnd/res/layout/purchase_dialog_osm_live_card.xml b/OsmAnd/res/layout/purchase_dialog_osm_live_card.xml index 9ac1fb62ed..20c35a3926 100644 --- a/OsmAnd/res/layout/purchase_dialog_osm_live_card.xml +++ b/OsmAnd/res/layout/purchase_dialog_osm_live_card.xml @@ -1,7 +1,6 @@ diff --git a/OsmAnd/res/values-id/strings.xml b/OsmAnd/res/values-id/strings.xml index ff0a3abcbe..5dc6196eff 100644 --- a/OsmAnd/res/values-id/strings.xml +++ b/OsmAnd/res/values-id/strings.xml @@ -713,7 +713,7 @@ Perpanjang tiap bulan Perpanjang tiap 4 bulan Perpanjang tiap tahun - + %1$.2f %2$s Pilih periode pembayaran yang anda inginkan: Sebagian pendapatan diberikan untuk kontributor OpenStreetMap. Oleh OsmAnd diff --git a/OsmAnd/res/values/attrs.xml b/OsmAnd/res/values/attrs.xml index 048cd83aca..28bdb7b983 100644 --- a/OsmAnd/res/values/attrs.xml +++ b/OsmAnd/res/values/attrs.xml @@ -103,6 +103,7 @@ + diff --git a/OsmAnd/res/values/colors.xml b/OsmAnd/res/values/colors.xml index 2d2f8ddb2d..59415b1a6a 100644 --- a/OsmAnd/res/values/colors.xml +++ b/OsmAnd/res/values/colors.xml @@ -461,7 +461,8 @@ #727272 - #1A237BFF + #1A237BFF + #1AD28521 #80237BFF #80000000 diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index fad1a692d0..83846ec978 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,8 @@ Thx - Hardy --> + Payment will be charged to your Google Play account at the confirmation of purchase.\n\nSubscription automatically renews unless it is canceled before the renewal date. Your account will be charged for renewal period(month/three month/year) only on the renewal date.\n\nYou can manage and cancel your subscriptions by going to your Google Play settings. + %1$s / %2$s Custom color Lombard Aragonese @@ -715,7 +717,7 @@ Annually %1$s / month %1$.2f %2$s / month - Save %1$s. + Save %1$s Current subscription Renews monthly Renews quarterly diff --git a/OsmAnd/res/values/styles.xml b/OsmAnd/res/values/styles.xml index 8fea939e8f..00bdab113b 100644 --- a/OsmAnd/res/values/styles.xml +++ b/OsmAnd/res/values/styles.xml @@ -246,6 +246,7 @@ @drawable/wikivoyage_primary_btn_bg_light @drawable/dialog_active_card_bg_light @drawable/purchase_dialog_shadow_btn_bg_light + @drawable/purchase_dialog_outline_btn_bg_light @drawable/bg_bottom_bar_shadow_with_line_day @@ -512,6 +513,7 @@ @drawable/wikivoyage_primary_btn_bg_dark @drawable/dialog_active_card_bg_dark @drawable/purchase_dialog_shadow_btn_bg_dark + @drawable/purchase_dialog_outline_btn_bg_dark @drawable/bg_bottom_bar_shadow_with_line_night diff --git a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java index 7a5f5876e2..2e220c7faf 100644 --- a/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java +++ b/OsmAnd/src/net/osmand/plus/chooseplan/ChoosePlanDialogFragment.java @@ -6,10 +6,12 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.res.Resources; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; @@ -37,6 +39,7 @@ import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; +import net.osmand.plus.UiUtilities; import net.osmand.plus.Version; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.base.BaseOsmAndDialogFragment; @@ -352,18 +355,21 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment osmLiveCardButtonsContainer.removeAllViews(); View lastBtn = null; List visibleSubscriptions = purchaseHelper.getLiveUpdates().getVisibleSubscriptions(); - boolean anyPurchasedOrIntroducted = false; + boolean anyPurchased = false; for (final InAppSubscription s : visibleSubscriptions) { - if (s.isPurchased() || s.getIntroductoryInfo() != null) { - anyPurchasedOrIntroducted = true; + if (s.isPurchased()) { + anyPurchased = true; break; } } + InAppSubscription subscriptionMaxDiscount = purchaseHelper.getLiveUpdates() + .getSubscriptionWithMaxDiscount(purchaseHelper.getMonthlyLiveUpdates()); + boolean maxDiscountAction = subscriptionMaxDiscount != null + && (subscriptionMaxDiscount.getIntroductoryInfo() != null || subscriptionMaxDiscount.isUpgrade()); for (final InAppSubscription s : visibleSubscriptions) { InAppSubscriptionIntroductoryInfo introductoryInfo = s.getIntroductoryInfo(); boolean hasIntroductoryInfo = introductoryInfo != null; - CharSequence descriptionText = hasIntroductoryInfo ? - introductoryInfo.getDescriptionTitle(ctx) : s.getDescription(ctx, purchaseHelper.getMonthlyLiveUpdates()); + CharSequence descriptionText = s.getDescription(ctx); if (s.isPurchased()) { View buttonPurchased = inflate(R.layout.purchase_dialog_card_button_active_ex, osmLiveCardButtonsContainer); TextViewEx title = (TextViewEx) buttonPurchased.findViewById(R.id.title); @@ -377,7 +383,7 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment AppCompatImageView rightImage = (AppCompatImageView) buttonPurchased.findViewById(R.id.right_image); CharSequence priceTitle = hasIntroductoryInfo ? - introductoryInfo.getFormattedDescription(ctx, buttonTitle.getCurrentTextColor()) : s.getPrice(ctx); + introductoryInfo.getFormattedDescription(ctx, buttonTitle.getCurrentTextColor()) : s.getPriceWithPeriod(ctx); title.setText(s.getTitle(ctx)); description.setText(descriptionText); buttonTitle.setText(priceTitle); @@ -421,45 +427,56 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment rightImage.setVisibility(View.VISIBLE); osmLiveCardButtonsContainer.addView(buttonCancel); lastBtn = buttonCancel; - } else { View button = inflate(R.layout.purchase_dialog_card_button_ex, osmLiveCardButtonsContainer); TextViewEx title = (TextViewEx) button.findViewById(R.id.title); TextViewEx description = (TextViewEx) button.findViewById(R.id.description); TextViewEx descriptionContribute = (TextViewEx) button.findViewById(R.id.description_contribute); descriptionContribute.setVisibility(s.isDonationSupported() ? View.VISIBLE : View.GONE); - - View buttonView = button.findViewById(R.id.button_view); View buttonExView = button.findViewById(R.id.button_ex_view); - TextViewEx buttonTitle = (TextViewEx) button.findViewById(R.id.button_title); TextViewEx buttonExTitle = (TextViewEx) button.findViewById(R.id.button_ex_title); - boolean showSolidButton = !anyPurchasedOrIntroducted || hasIntroductoryInfo; - buttonView.setVisibility(!showSolidButton ? View.VISIBLE : View.GONE); - buttonExView.setVisibility(showSolidButton ? View.VISIBLE : View.GONE); - View div = button.findViewById(R.id.div); - - CharSequence priceTitle = hasIntroductoryInfo ? - introductoryInfo.getFormattedDescription(ctx, buttonExTitle.getCurrentTextColor()) : s.getPrice(ctx); - title.setText(s.getTitle(ctx)); - description.setText(descriptionText); - buttonTitle.setText(priceTitle); - buttonExTitle.setText(priceTitle); - - if (!showSolidButton) { - buttonView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - subscribe(s.getSku()); - } - }); - } else { - buttonExView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - subscribe(s.getSku()); - } - }); + if (maxDiscountAction && s.equals(subscriptionMaxDiscount)) { + createSolidButton(ctx, buttonExView, buttonExTitle); } + CharSequence priceTitle = hasIntroductoryInfo ? + introductoryInfo.getFormattedDescription(ctx, buttonExTitle.getCurrentTextColor()) : s.getPriceWithPeriod(ctx); + buttonExTitle.setText(priceTitle); + title.setText(s.getTitle(ctx)); + if (Algorithms.isEmpty(descriptionText.toString())) { + description.setVisibility(View.GONE); + } else { + description.setText(descriptionText); + } + TextViewEx buttonDiscountTitle = (TextViewEx) button.findViewById(R.id.button_discount_title); + View buttonDiscountView = button.findViewById(R.id.button_discount_view); + String discountTitle = s.getDiscountTitle(ctx, purchaseHelper.getMonthlyLiveUpdates()); + if (!Algorithms.isEmpty(discountTitle)) { + buttonDiscountTitle.setText(discountTitle); + buttonDiscountView.setVisibility(View.VISIBLE); + } + if (s.equals(subscriptionMaxDiscount)) { + int saveTextColor = R.color.color_osm_edit_delete; + if (hasIntroductoryInfo) { + saveTextColor = R.color.active_buttons_and_links_text_light; + AndroidUtils.setBackground(buttonDiscountView, UiUtilities.tintDrawable(buttonDiscountView.getBackground(), + ContextCompat.getColor(ctx, R.color.color_osm_edit_delete))); + } + buttonDiscountTitle.setTextColor(ContextCompat.getColor(ctx, saveTextColor)); + } else { + if (maxDiscountAction) { + createOutlineButton(ctx, buttonExView, buttonExTitle); + } + } + if (anyPurchased) { + createOutlineButton(ctx, buttonExView, buttonExTitle); + } + buttonExView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + subscribe(s.getSku()); + } + }); + View div = button.findViewById(R.id.div); div.setVisibility(View.VISIBLE); osmLiveCardButtonsContainer.addView(button); lastBtn = button; @@ -478,6 +495,23 @@ public abstract class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment } } + private void createSolidButton(Context ctx, View buttonExView, TextViewEx buttonExTitle) { + Resources.Theme theme = ctx.getTheme(); + TypedValue typedValue = new TypedValue(); + theme.resolveAttribute(R.attr.wikivoyage_primary_btn_bg, typedValue, true); + buttonExView.setBackgroundResource(typedValue.resourceId); + buttonExTitle.setTextColor(ContextCompat.getColor(ctx, R.color.active_buttons_and_links_text_light)); + } + + private void createOutlineButton(Context ctx, View buttonExView, TextViewEx buttonExTitle) { + Resources.Theme theme = ctx.getTheme(); + TypedValue typedValue = new TypedValue(); + theme.resolveAttribute(R.attr.purchase_dialog_outline_btn_bg, typedValue, true); + buttonExView.setBackgroundResource(typedValue.resourceId); + theme.resolveAttribute(R.attr.color_dialog_buttons, typedValue, true); + buttonExTitle.setTextColor(ContextCompat.getColor(ctx, typedValue.resourceId)); + } + private void showDonationSettings() { FragmentActivity activity = getActivity(); if (activity != null) { diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java index 2fb216419e..cbe1de7b92 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppPurchases.java @@ -258,6 +258,20 @@ public class InAppPurchases { } return null; } + + @Nullable + public InAppSubscription getSubscriptionWithMaxDiscount(@Nullable InAppSubscription monthlyLiveUpdates) { + double maxDiscount = 0; + InAppSubscription subscriptionWithMaxDiscount = null; + for (InAppSubscription s : getAllSubscriptions()) { + double discount = s.getDiscountPercent(monthlyLiveUpdates); + if (discount > maxDiscount) { + subscriptionWithMaxDiscount = s; + maxDiscount = discount; + } + } + return subscriptionWithMaxDiscount; + } } public static class LiveUpdatesInAppPurchasesFree extends InAppSubscriptionList { @@ -677,6 +691,10 @@ public class InAppPurchases { return s; } + public boolean isUpgrade() { + return upgrade; + } + public boolean isAnyPurchased() { if (isPurchased()) { return true; @@ -728,6 +746,9 @@ public class InAppPurchases { @Override public CharSequence getDescription(@NonNull Context ctx) { + if (getMonthlyPriceValue() == getPriceValue()) { + return ""; + } if (getMonthlyPriceValue() == 0) { return ctx.getString(R.string.osm_live_payment_month_cost_descr, getDefaultMonthlyPrice(ctx)); } else { @@ -740,12 +761,6 @@ public class InAppPurchases { } } - public CharSequence getDescription(@NonNull Context ctx, @Nullable InAppSubscription monthlyLiveUpdates) { - CharSequence descr = getDescription(ctx); - int discountPercent = getDiscountPercent(monthlyLiveUpdates); - return discountPercent > 0 ? ctx.getString(R.string.price_and_discount, descr, discountPercent + "%") : descr; - } - public CharSequence getRenewDescription(@NonNull Context ctx) { return ""; } @@ -753,7 +768,12 @@ public class InAppPurchases { @Nullable protected abstract InAppSubscription newInstance(@NonNull String sku); - public int getDiscountPercent(@Nullable InAppSubscription monthlyLiveUpdates) { + public String getDiscountTitle(@NonNull Context ctx, @Nullable InAppSubscription monthlyLiveUpdates) { + int discountPercent = getDiscountPercent(monthlyLiveUpdates); + return discountPercent > 0 ? ctx.getString(R.string.osm_live_payment_discount_descr, discountPercent + "%") : ""; + } + + int getDiscountPercent(@Nullable InAppSubscription monthlyLiveUpdates) { double monthlyPriceValue = getMonthlyPriceValue(); if (monthlyLiveUpdates != null) { double regularMonthlyPrice = monthlyLiveUpdates.getPriceValue(); @@ -768,6 +788,10 @@ public class InAppPurchases { } return 0; } + + public String getPriceWithPeriod(Context ctx) { + return getPrice(ctx); + } } public static class InAppPurchaseFullVersion extends InAppPurchase { @@ -881,6 +905,12 @@ public class InAppPurchases { return ctx.getString(R.string.osm_live_payment_monthly_title); } + @Override + public String getPriceWithPeriod(Context ctx) { + return ctx.getString(R.string.ltr_or_rtl_combine_via_slash_with_space, getPrice(ctx), + ctx.getString(R.string.month).toLowerCase()); + } + @Override public CharSequence getRenewDescription(@NonNull Context ctx) { return ctx.getString(R.string.osm_live_payment_renews_monthly); @@ -956,6 +986,12 @@ public class InAppPurchases { return ctx.getString(R.string.osm_live_payment_3_months_title); } + @Override + public String getPriceWithPeriod(Context ctx) { + return ctx.getString(R.string.ltr_or_rtl_combine_via_slash_with_space, getPrice(ctx), + ctx.getString(R.string.months_3).toLowerCase()); + } + @Override public CharSequence getRenewDescription(@NonNull Context ctx) { return ctx.getString(R.string.osm_live_payment_renews_quarterly); @@ -1031,6 +1067,12 @@ public class InAppPurchases { return ctx.getString(R.string.osm_live_payment_annual_title); } + @Override + public String getPriceWithPeriod(Context ctx) { + return ctx.getString(R.string.ltr_or_rtl_combine_via_slash_with_space, getPrice(ctx), + ctx.getString(R.string.year).toLowerCase()); + } + @Override public CharSequence getRenewDescription(@NonNull Context ctx) { return ctx.getString(R.string.osm_live_payment_renews_annually);