Fix subscriptions new UI
This commit is contained in:
parent
0c6a7128ea
commit
d9baad5644
5 changed files with 309 additions and 103 deletions
|
@ -18,11 +18,12 @@ import net.osmand.plus.OsmandApplication;
|
|||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
|
||||
import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo;
|
||||
import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription;
|
||||
import net.osmand.plus.inapp.util.BillingManager;
|
||||
import net.osmand.plus.settings.backend.CommonPreference;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.srtmplugin.SRTMPlugin;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -310,8 +311,8 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (Entry<String, SubscriptionState> entry : subscriptionStateMap.entrySet()) {
|
||||
SubscriptionState state = entry.getValue();
|
||||
for (Entry<String, SubscriptionStateHolder> entry : subscriptionStateMap.entrySet()) {
|
||||
SubscriptionState state = entry.getValue().state;
|
||||
if (state == SubscriptionState.PAUSED || state == SubscriptionState.ON_HOLD) {
|
||||
String sku = entry.getKey();
|
||||
if (!result.contains(sku)) {
|
||||
|
@ -492,15 +493,17 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
|
|||
}
|
||||
|
||||
private PurchaseInfo getPurchaseInfo(Purchase purchase) {
|
||||
return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken());
|
||||
return new PurchaseInfo(purchase.getSku(), purchase.getOrderId(), purchase.getPurchaseToken(),
|
||||
purchase.getPurchaseTime(), purchase.getPurchaseState(), purchase.isAcknowledged(), purchase.isAutoRenewing());
|
||||
}
|
||||
|
||||
private void fetchInAppPurchase(@NonNull InAppPurchase inAppPurchase, @NonNull SkuDetails skuDetails, @Nullable Purchase purchase) {
|
||||
if (purchase != null) {
|
||||
inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.PURCHASED);
|
||||
inAppPurchase.setPurchaseTime(purchase.getPurchaseTime());
|
||||
inAppPurchase.setPurchaseState(PurchaseState.PURCHASED);
|
||||
inAppPurchase.setPurchaseInfo(ctx, getPurchaseInfo(purchase));
|
||||
} else {
|
||||
inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.NOT_PURCHASED);
|
||||
inAppPurchase.setPurchaseState(PurchaseState.NOT_PURCHASED);
|
||||
inAppPurchase.restorePurchaseInfo(ctx);
|
||||
}
|
||||
inAppPurchase.setPrice(skuDetails.getPrice());
|
||||
inAppPurchase.setPriceCurrencyCode(skuDetails.getPriceCurrencyCode());
|
||||
|
@ -519,18 +522,17 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
|
|||
}
|
||||
if (inAppPurchase instanceof InAppSubscription) {
|
||||
InAppSubscription s = (InAppSubscription) inAppPurchase;
|
||||
|
||||
SubscriptionState state = subscriptionStateMap.get(inAppPurchase.getSku());
|
||||
s.setState(state == null ? SubscriptionState.UNDEFINED : state);
|
||||
CommonPreference<String> statePref = ctx.getSettings().registerStringPreference(
|
||||
s.getSku() + "_state", SubscriptionState.UNDEFINED.getStateStr()).makeGlobal();
|
||||
s.setPrevState(SubscriptionState.getByStateStr(statePref.get()));
|
||||
statePref.set(s.getState().getStateStr());
|
||||
s.restoreState(ctx);
|
||||
s.restoreExpireTime(ctx);
|
||||
SubscriptionStateHolder stateHolder = subscriptionStateMap.get(s.getSku());
|
||||
if (stateHolder != null) {
|
||||
s.setState(ctx, stateHolder.state);
|
||||
s.setExpireTime(ctx, stateHolder.expireTime);
|
||||
}
|
||||
if (s.getState().isGone() && s.hasStateChanged()) {
|
||||
ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L);
|
||||
ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L);
|
||||
}
|
||||
|
||||
String introductoryPrice = skuDetails.getIntroductoryPrice();
|
||||
String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
|
||||
int introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
|
||||
|
|
|
@ -29,6 +29,7 @@ import net.osmand.plus.OsmandApplication;
|
|||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionIntroductoryInfo;
|
||||
import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo;
|
||||
import net.osmand.plus.inapp.InAppPurchasesImpl.InAppPurchaseLiveUpdatesOldSubscription;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -48,7 +49,7 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
|
|||
|
||||
private List<ProductInfo> productInfos;
|
||||
private OwnedPurchasesResult ownedSubscriptions;
|
||||
private List<OwnedPurchasesResult> ownedInApps = new ArrayList<>();
|
||||
private final List<OwnedPurchasesResult> ownedInApps = new ArrayList<>();
|
||||
|
||||
public InAppPurchaseHelperImpl(OsmandApplication ctx) {
|
||||
super(ctx);
|
||||
|
@ -233,15 +234,18 @@ public class InAppPurchaseHelperImpl extends InAppPurchaseHelper {
|
|||
}
|
||||
|
||||
private PurchaseInfo getPurchaseInfo(InAppPurchaseData purchase) {
|
||||
return new PurchaseInfo(purchase.getProductId(), purchase.getSubscriptionId(), purchase.getPurchaseToken());
|
||||
return new PurchaseInfo(purchase.getProductId(), purchase.getSubscriptionId(), purchase.getPurchaseToken(),
|
||||
purchase.getPurchaseTime(), purchase.getPurchaseState(), true, purchase.isAutoRenewing());
|
||||
}
|
||||
|
||||
private void fetchInAppPurchase(@NonNull InAppPurchase inAppPurchase, @NonNull ProductInfo productInfo, @Nullable InAppPurchaseData purchaseData) {
|
||||
if (purchaseData != null) {
|
||||
inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.PURCHASED);
|
||||
inAppPurchase.setPurchaseTime(purchaseData.getPurchaseTime());
|
||||
inAppPurchase.setPurchaseInfo(ctx, getPurchaseInfo(purchaseData));
|
||||
} else {
|
||||
inAppPurchase.setPurchaseState(InAppPurchase.PurchaseState.NOT_PURCHASED);
|
||||
inAppPurchase.restorePurchaseInfo(ctx);
|
||||
}
|
||||
inAppPurchase.setPrice(productInfo.getPrice());
|
||||
inAppPurchase.setPriceCurrencyCode(productInfo.getCurrency());
|
||||
|
|
|
@ -21,6 +21,7 @@ import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
|
|||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
|
||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList;
|
||||
import net.osmand.plus.inapp.InAppPurchases.PurchaseInfo;
|
||||
import net.osmand.plus.liveupdates.CountrySelectionFragment;
|
||||
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
|
@ -52,7 +53,7 @@ public abstract class InAppPurchaseHelper {
|
|||
protected InAppPurchases purchases;
|
||||
protected long lastValidationCheckTime;
|
||||
protected boolean inventoryRequested;
|
||||
protected Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
|
||||
protected Map<String, SubscriptionStateHolder> subscriptionStateMap = new HashMap<>();
|
||||
|
||||
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
|
||||
|
||||
|
@ -85,6 +86,11 @@ public abstract class InAppPurchaseHelper {
|
|||
void onFail();
|
||||
}
|
||||
|
||||
static class SubscriptionStateHolder {
|
||||
SubscriptionState state = SubscriptionState.UNDEFINED;
|
||||
long expireTime = 0;
|
||||
}
|
||||
|
||||
public enum InAppPurchaseTaskType {
|
||||
REQUEST_INVENTORY,
|
||||
PURCHASE_FULL_VERSION,
|
||||
|
@ -112,30 +118,6 @@ public abstract class InAppPurchaseHelper {
|
|||
void onCommandDone(@NonNull InAppCommand command);
|
||||
}
|
||||
|
||||
public static class PurchaseInfo {
|
||||
private String sku;
|
||||
private String orderId;
|
||||
private String purchaseToken;
|
||||
|
||||
public PurchaseInfo(String sku, String orderId, String purchaseToken) {
|
||||
this.sku = sku;
|
||||
this.orderId = orderId;
|
||||
this.purchaseToken = purchaseToken;
|
||||
}
|
||||
|
||||
public String getSku() {
|
||||
return sku;
|
||||
}
|
||||
|
||||
public String getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public String getPurchaseToken() {
|
||||
return purchaseToken;
|
||||
}
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
@ -193,6 +175,11 @@ public abstract class InAppPurchaseHelper {
|
|||
return purchases.getPurchasedMonthlyLiveUpdates();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InAppSubscription getAnyPurchasedSubscription() {
|
||||
return purchases.getAnyPurchasedSubscription();
|
||||
}
|
||||
|
||||
public InAppPurchaseHelper(OsmandApplication ctx) {
|
||||
this.ctx = ctx;
|
||||
isDeveloperVersion = Version.isDeveloperVersion(ctx);
|
||||
|
@ -202,8 +189,7 @@ public abstract class InAppPurchaseHelper {
|
|||
public List<InAppSubscription> getEverMadeSubscriptions() {
|
||||
List<InAppSubscription> subscriptions = new ArrayList<>();
|
||||
for (InAppSubscription subscription : getLiveUpdates().getVisibleSubscriptions()) {
|
||||
SubscriptionState state = subscription.getState();
|
||||
if (state != SubscriptionState.UNDEFINED) {
|
||||
if (subscription.isPurchased() || subscription.getState() != SubscriptionState.UNDEFINED) {
|
||||
subscriptions.add(subscription);
|
||||
}
|
||||
}
|
||||
|
@ -448,15 +434,22 @@ public abstract class InAppPurchaseHelper {
|
|||
}
|
||||
if (subscriptionsStateJson != null) {
|
||||
inventoryRequested = true;
|
||||
Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
|
||||
Map<String, SubscriptionStateHolder> subscriptionStateMap = new HashMap<>();
|
||||
try {
|
||||
JSONArray subArrJson = new JSONArray(subscriptionsStateJson);
|
||||
for (int i = 0; i < subArrJson.length(); i++) {
|
||||
JSONObject subObj = subArrJson.getJSONObject(i);
|
||||
String sku = subObj.getString("sku");
|
||||
String state = subObj.getString("state");
|
||||
long expireTime = 0;
|
||||
if (subObj.has("expire_time")) {
|
||||
expireTime = subObj.getLong("expire_time");
|
||||
}
|
||||
if (!Algorithms.isEmpty(sku) && !Algorithms.isEmpty(state)) {
|
||||
subscriptionStateMap.put(sku, SubscriptionState.getByStateStr(state));
|
||||
SubscriptionStateHolder stateHolder = new SubscriptionStateHolder();
|
||||
stateHolder.state = SubscriptionState.getByStateStr(state);
|
||||
stateHolder.expireTime = expireTime;
|
||||
subscriptionStateMap.put(sku, stateHolder);
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
@ -500,12 +493,14 @@ public abstract class InAppPurchaseHelper {
|
|||
protected void onPurchaseDone(PurchaseInfo info) {
|
||||
logDebug("Purchase successful.");
|
||||
|
||||
InAppPurchase liveUpdatesPurchase = getLiveUpdates().getSubscriptionBySku(info.getSku());
|
||||
InAppSubscription liveUpdatesPurchase = getLiveUpdates().getSubscriptionBySku(info.getSku());
|
||||
if (liveUpdatesPurchase != null) {
|
||||
// bought live updates
|
||||
logDebug("Live updates subscription purchased.");
|
||||
final String sku = liveUpdatesPurchase.getSku();
|
||||
liveUpdatesPurchase.setPurchaseState(PurchaseState.PURCHASED);
|
||||
liveUpdatesPurchase.setPurchaseInfo(ctx, info);
|
||||
liveUpdatesPurchase.setState(ctx, SubscriptionState.UNDEFINED);
|
||||
sendTokens(Collections.singletonList(info), new OnRequestResultListener() {
|
||||
@Override
|
||||
public void onResult(String result) {
|
||||
|
@ -525,6 +520,7 @@ public abstract class InAppPurchaseHelper {
|
|||
} else if (info.getSku().equals(getFullVersion().getSku())) {
|
||||
// bought full version
|
||||
getFullVersion().setPurchaseState(PurchaseState.PURCHASED);
|
||||
getFullVersion().setPurchaseInfo(ctx, info);
|
||||
logDebug("Full version purchased.");
|
||||
showToast(ctx.getString(R.string.full_version_thanks));
|
||||
ctx.getSettings().FULL_VERSION_PURCHASED.set(true);
|
||||
|
@ -536,6 +532,7 @@ public abstract class InAppPurchaseHelper {
|
|||
} else if (info.getSku().equals(getDepthContours().getSku())) {
|
||||
// bought sea depth contours
|
||||
getDepthContours().setPurchaseState(PurchaseState.PURCHASED);
|
||||
getDepthContours().setPurchaseInfo(ctx, info);
|
||||
logDebug("Sea depth contours purchased.");
|
||||
showToast(ctx.getString(R.string.sea_depth_thanks));
|
||||
ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true);
|
||||
|
@ -548,6 +545,7 @@ public abstract class InAppPurchaseHelper {
|
|||
} else if (info.getSku().equals(getContourLines().getSku())) {
|
||||
// bought contour lines
|
||||
getContourLines().setPurchaseState(PurchaseState.PURCHASED);
|
||||
getContourLines().setPurchaseInfo(ctx, info);
|
||||
logDebug("Contours lines purchased.");
|
||||
showToast(ctx.getString(R.string.contour_lines_thanks));
|
||||
ctx.getSettings().CONTOUR_LINES_PURCHASED.set(true);
|
||||
|
|
|
@ -7,33 +7,41 @@ import android.text.Spannable;
|
|||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.Period;
|
||||
import net.osmand.Period.PeriodUnit;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.helpers.FontCache;
|
||||
import net.osmand.plus.settings.backend.CommonPreference;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.widgets.style.CustomTypefaceSpan;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Currency;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
public abstract class InAppPurchases {
|
||||
|
||||
protected InAppPurchase fullVersion;
|
||||
|
@ -47,6 +55,10 @@ public abstract class InAppPurchases {
|
|||
protected InAppPurchases(OsmandApplication ctx) {
|
||||
}
|
||||
|
||||
private static OsmandSettings getSettings(@NonNull Context ctx) {
|
||||
return ((OsmandApplication) ctx.getApplicationContext()).getSettings();
|
||||
}
|
||||
|
||||
public InAppPurchase getFullVersion() {
|
||||
return fullVersion;
|
||||
}
|
||||
|
@ -83,6 +95,17 @@ public abstract class InAppPurchases {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InAppSubscription getAnyPurchasedSubscription() {
|
||||
List<InAppSubscription> allSubscriptions = liveUpdates.getAllSubscriptions();
|
||||
for (InAppSubscription subscription : allSubscriptions) {
|
||||
if (subscription.isAnyPurchased()) {
|
||||
return subscription;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public InAppSubscriptionList getLiveUpdates() {
|
||||
return liveUpdates;
|
||||
}
|
||||
|
@ -231,7 +254,7 @@ public abstract class InAppPurchases {
|
|||
private double priceValue;
|
||||
private String priceCurrencyCode;
|
||||
private PurchaseState purchaseState = PurchaseState.UNKNOWN;
|
||||
private long purchaseTime;
|
||||
private PurchaseInfo purchaseInfo;
|
||||
|
||||
double monthlyPriceValue;
|
||||
boolean donationSupported = false;
|
||||
|
@ -253,6 +276,37 @@ public abstract class InAppPurchases {
|
|||
return sku;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getOrderId() {
|
||||
return purchaseInfo != null ? purchaseInfo.getOrderId() : null;
|
||||
}
|
||||
|
||||
private CommonPreference<String> getPurchaseInfoPref(@NonNull Context ctx) {
|
||||
return getSettings(ctx).registerStringPreference(sku + "_purchase_info", "").makeGlobal();
|
||||
}
|
||||
|
||||
public boolean storePurchaseInfo(@NonNull Context ctx) {
|
||||
PurchaseInfo purchaseInfo = this.purchaseInfo;
|
||||
if (purchaseInfo != null) {
|
||||
getPurchaseInfoPref(ctx).set(purchaseInfo.toJson());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean restorePurchaseInfo(@NonNull Context ctx) {
|
||||
String json = getPurchaseInfoPref(ctx).get();
|
||||
if (!Algorithms.isEmpty(json)) {
|
||||
try {
|
||||
purchaseInfo = new PurchaseInfo(json);
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPrice(Context ctx) {
|
||||
if (!Algorithms.isEmpty(price)) {
|
||||
return price;
|
||||
|
@ -266,11 +320,16 @@ public abstract class InAppPurchases {
|
|||
}
|
||||
|
||||
public long getPurchaseTime() {
|
||||
return purchaseTime;
|
||||
return purchaseInfo != null ? purchaseInfo.getPurchaseTime() : 0;
|
||||
}
|
||||
|
||||
public void setPurchaseTime(long purchaseTime) {
|
||||
this.purchaseTime = purchaseTime;
|
||||
public PurchaseInfo getPurchaseInfo() {
|
||||
return purchaseInfo;
|
||||
}
|
||||
|
||||
void setPurchaseInfo(@NonNull Context ctx, PurchaseInfo purchaseInfo) {
|
||||
this.purchaseInfo = purchaseInfo;
|
||||
storePurchaseInfo(ctx);
|
||||
}
|
||||
|
||||
public String getDefaultPrice(Context ctx) {
|
||||
|
@ -571,35 +630,33 @@ public abstract class InAppPurchases {
|
|||
|
||||
public static abstract class InAppSubscription extends InAppPurchase {
|
||||
|
||||
private Map<String, InAppSubscription> upgrades = new ConcurrentHashMap<>();
|
||||
private String skuNoVersion;
|
||||
private final Map<String, InAppSubscription> upgrades = new ConcurrentHashMap<>();
|
||||
private final String skuNoVersion;
|
||||
private String subscriptionPeriodString;
|
||||
private Period subscriptionPeriod;
|
||||
private boolean upgrade = false;
|
||||
private SubscriptionState state = SubscriptionState.UNDEFINED;
|
||||
private SubscriptionState prevState = SubscriptionState.UNDEFINED;
|
||||
private SubscriptionState previousState = SubscriptionState.UNDEFINED;
|
||||
private long expireTime = 0;
|
||||
|
||||
private InAppSubscriptionIntroductoryInfo introductoryInfo;
|
||||
|
||||
public enum SubscriptionState {
|
||||
UNDEFINED("undefined", 0, 0),
|
||||
ACTIVE("active", R.string.osm_live_active, R.drawable.bg_osmand_live_active),
|
||||
CANCELLED("cancelled", R.string.osmand_live_cancelled, R.drawable.bg_osmand_live_cancelled),
|
||||
IN_GRACE_PERIOD("in_grace_period", R.string.in_grace_period, R.drawable.bg_osmand_live_active),
|
||||
ON_HOLD("on_hold", R.string.on_hold, R.drawable.bg_osmand_live_cancelled),
|
||||
PAUSED("paused", R.string.shared_string_paused, R.drawable.bg_osmand_live_cancelled),
|
||||
EXPIRED("expired", R.string.expired, R.drawable.bg_osmand_live_cancelled);
|
||||
UNDEFINED("undefined", R.string.shared_string_undefined),
|
||||
ACTIVE("active", R.string.osm_live_active),
|
||||
CANCELLED("cancelled", R.string.osmand_live_cancelled),
|
||||
IN_GRACE_PERIOD("in_grace_period", R.string.in_grace_period),
|
||||
ON_HOLD("on_hold", R.string.on_hold),
|
||||
PAUSED("paused", R.string.shared_string_paused),
|
||||
EXPIRED("expired", R.string.expired);
|
||||
|
||||
private final String stateStr;
|
||||
@StringRes
|
||||
private final int stringRes;
|
||||
@DrawableRes
|
||||
private final int backgroundRes;
|
||||
|
||||
SubscriptionState(@NonNull String stateStr, @StringRes int stringRes, @DrawableRes int backgroundRes) {
|
||||
SubscriptionState(@NonNull String stateStr, @StringRes int stringRes) {
|
||||
this.stateStr = stateStr;
|
||||
this.stringRes = stringRes;
|
||||
this.backgroundRes = backgroundRes;
|
||||
}
|
||||
|
||||
public String getStateStr() {
|
||||
|
@ -611,11 +668,6 @@ public abstract class InAppPurchases {
|
|||
return stringRes;
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
public int getBackgroundRes() {
|
||||
return backgroundRes;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static SubscriptionState getByStateStr(@NonNull String stateStr) {
|
||||
for (SubscriptionState state : SubscriptionState.values()) {
|
||||
|
@ -678,21 +730,76 @@ public abstract class InAppPurchases {
|
|||
return state;
|
||||
}
|
||||
|
||||
public void setState(@NonNull SubscriptionState state) {
|
||||
public void setState(@NonNull Context ctx, @NonNull SubscriptionState state) {
|
||||
this.state = state;
|
||||
storeState(ctx, state);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SubscriptionState getPrevState() {
|
||||
return prevState;
|
||||
}
|
||||
|
||||
public void setPrevState(@NonNull SubscriptionState prevState) {
|
||||
this.prevState = prevState;
|
||||
public SubscriptionState getPreviousState() {
|
||||
return previousState;
|
||||
}
|
||||
|
||||
public boolean hasStateChanged() {
|
||||
return state != prevState;
|
||||
return state != previousState;
|
||||
}
|
||||
|
||||
private CommonPreference<String> getStatePref(@NonNull Context ctx) {
|
||||
return getSettings(ctx).registerStringPreference(getSku() + "_state", "").makeGlobal();
|
||||
}
|
||||
|
||||
void storeState(@NonNull Context ctx, @NonNull SubscriptionState state) {
|
||||
getStatePref(ctx).set(state.getStateStr());
|
||||
}
|
||||
|
||||
boolean restoreState(@NonNull Context ctx) {
|
||||
String stateStr = getStatePref(ctx).get();
|
||||
if (!Algorithms.isEmpty(stateStr)) {
|
||||
SubscriptionState state = SubscriptionState.getByStateStr(stateStr);
|
||||
this.previousState = state;
|
||||
this.state = state;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getCalculatedExpiredTime() {
|
||||
long purchaseTime = getPurchaseTime();
|
||||
Period period = getSubscriptionPeriod();
|
||||
if (purchaseTime == 0 || period == null || period.getUnit() == null) {
|
||||
return 0;
|
||||
}
|
||||
Date date = new Date(purchaseTime);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(period.getUnit().getCalendarIdx(), period.getNumberOfUnits());
|
||||
return calendar.getTimeInMillis();
|
||||
}
|
||||
|
||||
public long getExpireTime() {
|
||||
return expireTime;
|
||||
}
|
||||
|
||||
public void setExpireTime(@NonNull Context ctx, long expireTime) {
|
||||
this.expireTime = expireTime;
|
||||
storeExpireTime(ctx, expireTime);
|
||||
}
|
||||
|
||||
private CommonPreference<Long> getExpireTimePref(@NonNull Context ctx) {
|
||||
return getSettings(ctx).registerLongPreference(getSku() + "_expire_time", 0L).makeGlobal();
|
||||
}
|
||||
|
||||
boolean restoreExpireTime(@NonNull Context ctx) {
|
||||
Long expireTime = getExpireTimePref(ctx).get();
|
||||
if (expireTime != null) {
|
||||
this.expireTime = expireTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void storeExpireTime(@NonNull Context ctx, long expireTime) {
|
||||
getExpireTimePref(ctx).set(expireTime);
|
||||
}
|
||||
|
||||
public boolean isAnyPurchased() {
|
||||
|
@ -999,5 +1106,95 @@ public abstract class InAppPurchases {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PurchaseInfo {
|
||||
private String sku;
|
||||
private String orderId;
|
||||
private String purchaseToken;
|
||||
private long purchaseTime;
|
||||
private int purchaseState;
|
||||
private boolean acknowledged;
|
||||
private boolean autoRenewing;
|
||||
|
||||
PurchaseInfo(String sku, String orderId, String purchaseToken, long purchaseTime,
|
||||
int purchaseState, boolean acknowledged, boolean autoRenewing) {
|
||||
this.sku = sku;
|
||||
this.orderId = orderId;
|
||||
this.purchaseToken = purchaseToken;
|
||||
this.purchaseTime = purchaseTime;
|
||||
this.purchaseState = purchaseState;
|
||||
this.acknowledged = acknowledged;
|
||||
this.autoRenewing = autoRenewing;
|
||||
}
|
||||
|
||||
PurchaseInfo(@NonNull String json) throws JSONException {
|
||||
parseJson(json);
|
||||
}
|
||||
|
||||
public String getSku() {
|
||||
return sku;
|
||||
}
|
||||
|
||||
public String getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public String getPurchaseToken() {
|
||||
return purchaseToken;
|
||||
}
|
||||
|
||||
public long getPurchaseTime() {
|
||||
return purchaseTime;
|
||||
}
|
||||
|
||||
public int getPurchaseState() {
|
||||
return purchaseState;
|
||||
}
|
||||
|
||||
public boolean isAcknowledged() {
|
||||
return acknowledged;
|
||||
}
|
||||
|
||||
public boolean isAutoRenewing() {
|
||||
return autoRenewing;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
Map<String, Object> jsonMap = new HashMap<>();
|
||||
jsonMap.put("sku", sku);
|
||||
jsonMap.put("orderId", orderId);
|
||||
jsonMap.put("purchaseToken", purchaseToken);
|
||||
jsonMap.put("purchaseTime", purchaseTime);
|
||||
jsonMap.put("purchaseState", purchaseState);
|
||||
jsonMap.put("acknowledged", acknowledged);
|
||||
jsonMap.put("autoRenewing", autoRenewing);
|
||||
return new JSONObject(jsonMap).toString();
|
||||
}
|
||||
|
||||
public void parseJson(@NonNull String json) throws JSONException {
|
||||
JSONObject jsonObj = new JSONObject(json);
|
||||
if (jsonObj.has("sku")) {
|
||||
this.sku = jsonObj.getString("sku");
|
||||
}
|
||||
if (jsonObj.has("orderId")) {
|
||||
this.orderId = jsonObj.getString("orderId");
|
||||
}
|
||||
if (jsonObj.has("purchaseToken")) {
|
||||
this.purchaseToken = jsonObj.getString("purchaseToken");
|
||||
}
|
||||
if (jsonObj.has("purchaseTime")) {
|
||||
this.purchaseTime = jsonObj.getLong("purchaseTime");
|
||||
}
|
||||
if (jsonObj.has("purchaseState")) {
|
||||
this.purchaseState = jsonObj.getInt("purchaseState");
|
||||
}
|
||||
if (jsonObj.has("acknowledged")) {
|
||||
this.acknowledged = jsonObj.getBoolean("acknowledged");
|
||||
}
|
||||
if (jsonObj.has("autoRenewing")) {
|
||||
this.autoRenewing = jsonObj.getBoolean("autoRenewing");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.view.ViewGroup;
|
|||
import android.widget.TextView;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.Period;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
|
@ -20,11 +19,10 @@ import net.osmand.plus.routepreparationmenu.cards.BaseCard;
|
|||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class SubscriptionsListCard extends BaseCard {
|
||||
|
@ -60,7 +58,13 @@ public class SubscriptionsListCard extends BaseCard {
|
|||
for (int i = 0; i < subscriptions.size(); i++) {
|
||||
InAppSubscription subscription = subscriptions.get(i);
|
||||
SubscriptionState state = subscription.getState();
|
||||
boolean autoRenewed = state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD;
|
||||
boolean autoRenewing = false;
|
||||
if (subscription.isPurchased() && subscription.getPurchaseInfo() != null) {
|
||||
autoRenewing = subscription.getPurchaseInfo().isAutoRenewing();
|
||||
state = SubscriptionState.ACTIVE;
|
||||
} else if (state != SubscriptionState.UNDEFINED) {
|
||||
autoRenewing = state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD;
|
||||
}
|
||||
|
||||
View card = inflater.inflate(R.layout.subscription_layout, null, false);
|
||||
((ViewGroup) view).addView(card);
|
||||
|
@ -72,11 +76,18 @@ public class SubscriptionsListCard extends BaseCard {
|
|||
AndroidUiHelper.updateVisibility(subscriptionPeriod, true);
|
||||
}
|
||||
|
||||
if (autoRenewed) {
|
||||
if (autoRenewing) {
|
||||
TextView nextBillingDate = card.findViewById(R.id.next_billing_date);
|
||||
String date = getHumanDate(subscription.getPurchaseTime(), subscription.getSubscriptionPeriod());
|
||||
if (!Algorithms.isEmpty(date)) {
|
||||
nextBillingDate.setText(app.getString(R.string.next_billing_date, date));
|
||||
String expiredTimeStr = null;
|
||||
long expiredTime = subscription.getExpireTime();
|
||||
if (expiredTime == 0) {
|
||||
expiredTime = subscription.getCalculatedExpiredTime();
|
||||
}
|
||||
if (expiredTime > 0) {
|
||||
expiredTimeStr = dateFormat.format(expiredTime);
|
||||
}
|
||||
if (!Algorithms.isEmpty(expiredTimeStr)) {
|
||||
nextBillingDate.setText(app.getString(R.string.next_billing_date, expiredTimeStr));
|
||||
AndroidUiHelper.updateVisibility(nextBillingDate, true);
|
||||
}
|
||||
} else {
|
||||
|
@ -102,7 +113,7 @@ public class SubscriptionsListCard extends BaseCard {
|
|||
|
||||
TextView status = card.findViewById(R.id.status);
|
||||
status.setText(app.getString(state.getStringRes()));
|
||||
AndroidUtils.setBackground(status, app.getUIUtilities().getIcon(state.getBackgroundRes()));
|
||||
AndroidUtils.setBackground(status, app.getUIUtilities().getIcon(getBackgroundRes(state)));
|
||||
|
||||
int dividerLayout = i + 1 == subscriptions.size() ? R.layout.simple_divider_item : R.layout.divider_half_item;
|
||||
View divider = inflater.inflate(dividerLayout, (ViewGroup) view, false);
|
||||
|
@ -110,15 +121,9 @@ public class SubscriptionsListCard extends BaseCard {
|
|||
}
|
||||
}
|
||||
|
||||
private String getHumanDate(long time, Period period) {
|
||||
if (period == null || period.getUnit() == null) {
|
||||
return "";
|
||||
}
|
||||
Date date = new Date(time);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(period.getUnit().getCalendarIdx(), period.getNumberOfUnits());
|
||||
date = calendar.getTime();
|
||||
return dateFormat.format(date);
|
||||
@DrawableRes
|
||||
private int getBackgroundRes(@NonNull SubscriptionState state) {
|
||||
return state == SubscriptionState.ACTIVE || state == SubscriptionState.IN_GRACE_PERIOD
|
||||
? R.drawable.bg_osmand_live_active : R.drawable.bg_osmand_live_cancelled;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue