Skip to content

Commit

Permalink
Merge pull request #317 from ivpn/task/pending-payments
Browse files Browse the repository at this point in the history
Improve UX for pending payments
  • Loading branch information
jurajhilje authored Jun 3, 2024
2 parents 0d11161 + e14e03b commit c392d73
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ public void createPurchaseErrorDialog(String errorCode, String errorMessage) {
});
}

@Override
public void createDialog(String title, String message) {
DialogBuilder.createFullCustomNotificationDialog(this,
title,
message, dialog -> {
BillingActivity.this.finish();
});
}

@Override
public void onAccountCreated() {
finish();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@

import javax.inject.Inject;

import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.ADD_FUNDS_ERROR;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.CREATE_SESSION;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.CREATE_SESSION_ERROR;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.INITIAL_PAYMENT;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.INITIAL_PAYMENT_ERROR;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.UPDATE_SESSION;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.UPDATE_SESSION_ERROR;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.PAYMENT_PENDING;
import static net.ivpn.client.billing.BillingManagerWrapper.PurchaseState.INITIAL_PAYMENT_PENDING;

@BillingScope
public class BillingManagerWrapper {
Expand Down Expand Up @@ -130,8 +133,20 @@ public void onPurchasesUpdated(List<Purchase> purchases) {
&& ConsumableProducts.INSTANCE.getConsumableSKUs().contains(purchase.getProducts().get(0))) {
billingManager.consumePurchase(purchase);
}

if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING) {
String sessionToken = userPreference.getSessionToken();
if (sessionToken.isEmpty()) {
setPurchaseState(INITIAL_PAYMENT_PENDING);
} else {
setPurchaseState(PAYMENT_PENDING);
}
}

if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
startValidatingActivity(purchase);
}
}
startValidatingActivity(purchases.get(0));
}

@Override
Expand Down Expand Up @@ -268,18 +283,18 @@ public void onSuccess(AddFundsResponse response) {
if (response.getStatus() == Responses.SUCCESS) {
updateSession();
} else {
setPurchaseState(INITIAL_PAYMENT_ERROR);
setPurchaseState(ADD_FUNDS_ERROR);
}
}

@Override
public void onError(Throwable throwable) {
setPurchaseState(INITIAL_PAYMENT_ERROR);
setPurchaseState(ADD_FUNDS_ERROR);
}

@Override
public void onError(String string) {
setPurchaseState(INITIAL_PAYMENT_ERROR);
setPurchaseState(ADD_FUNDS_ERROR);
}
});
}
Expand Down Expand Up @@ -346,6 +361,8 @@ public enum PurchaseState {
CREATE_SESSION_ERROR,
UPDATE_SESSION,
UPDATE_SESSION_ERROR,
ADD_FUNDS_ERROR
ADD_FUNDS_ERROR,
PAYMENT_PENDING,
INITIAL_PAYMENT_PENDING
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public interface BillingNavigator {

void createPurchaseErrorDialog(String errorCode, String errorMessage);

void createDialog(String title, String message);

void onAccountCreated();

void onAddFundsFinish();
Expand Down
42 changes: 23 additions & 19 deletions store/src/main/java/net/ivpn/client/billing/BillingViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,39 +72,43 @@ public void onInitStateChanged(boolean isInit, int error) {
public void onPurchaseStateChanged(BillingManagerWrapper.PurchaseState state) {
LOGGER.info("PurchaseState = " + state);
switch (state) {
case NONE:
dataLoading.set(false);
break;
case INITIAL_PAYMENT:
case PURCHASING:
case VALIDATING:
case NONE -> dataLoading.set(false);
case INITIAL_PAYMENT, PURCHASING, VALIDATING -> {
dataLoading.set(true);
processDescription.set(getString(R.string.billing_validating));
break;
case CREATE_ACCOUNT:
}
case CREATE_ACCOUNT -> {
dataLoading.set(true);
processDescription.set(getString(R.string.billing_creating_account));
break;
case CREATE_SESSION:
}
case CREATE_SESSION -> {
dataLoading.set(true);
processDescription.set(getString(R.string.billing_creating_new_session));
break;
case INITIAL_PAYMENT_ERROR:
}
case INITIAL_PAYMENT_ERROR -> {
dataLoading.set(false);
navigator.createPurchaseErrorDialog("", "There was an error while creating your account. Contact our support or reopen the application to try again.");
break;
case ADD_FUNDS_ERROR:
}
case ADD_FUNDS_ERROR -> {
dataLoading.set(false);
navigator.createPurchaseErrorDialog("", "There was an error while adding funds to your account. Contact our support or reopen the application to try again.");
break;
case UPDATE_SESSION_ERROR:
}
case PAYMENT_PENDING -> {
dataLoading.set(false);
navigator.createDialog("Pending payment", "Payment is pending for approval. We will complete the transaction as soon as payment is approved.");
}
case INITIAL_PAYMENT_PENDING -> {
dataLoading.set(false);
navigator.createDialog("Pending payment", "Payment is pending for approval. We will complete the transaction as soon as payment is approved.");
}
case UPDATE_SESSION_ERROR -> {
dataLoading.set(false);
navigator.createPurchaseErrorDialog("", "There was an error while updating your session. Contact our support or reopen the application to try again.");
break;
case DONE:
}
case DONE -> {
dataLoading.set(false);
navigator.onSuccessBilling();
break;
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions store/src/main/java/net/ivpn/client/signup/SignUpPeriodFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,22 @@ class SignUpPeriodFragment : Fragment(), SignUpViewModel.SignUpNavigator {
}
}
}

override fun createDialog(title: String?, message: String?) {
if (activity != null) {
DialogBuilder.createFullCustomNotificationDialog(activity, title,
message) {
findNavControllerSafely()?.popBackStack()
}
}
}

override fun createInitialDialog(title: String?, message: String?) {
if (activity != null) {
DialogBuilder.createFullCustomNotificationDialog(activity, title,
message) {
findNavControllerSafely()?.navigate(net.ivpn.core.R.id.connectFragment)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,22 @@ class SignUpProductFragment : Fragment(), SignUpViewModel.SignUpNavigator {
}
}
}

override fun createDialog(title: String?, message: String?) {
if (activity != null) {
DialogBuilder.createFullCustomNotificationDialog(activity, title,
message) {
findNavControllerSafely()?.popBackStack()
}
}
}

override fun createInitialDialog(title: String?, message: String?) {
if (activity != null) {
DialogBuilder.createFullCustomNotificationDialog(activity, title,
message) {
findNavControllerSafely()?.navigate(net.ivpn.core.R.id.connectFragment)
}
}
}
}
24 changes: 22 additions & 2 deletions store/src/main/java/net/ivpn/client/signup/SignUpViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ import net.ivpn.core.rest.requests.common.Request
import net.ivpn.core.rest.requests.common.RequestWrapper
import net.ivpn.core.v2.signup.SignUpController
import org.slf4j.LoggerFactory
import java.util.*
import java.util.Calendar
import javax.inject.Inject
import kotlin.collections.ArrayList
import kotlin.math.floor

@BillingScope
Expand Down Expand Up @@ -360,6 +359,23 @@ class SignUpViewModel @Inject constructor(
}

override fun onPurchaseStateChanged(state: BillingManagerWrapper.PurchaseState?) {
when (state) {
BillingManagerWrapper.PurchaseState.PAYMENT_PENDING -> {
navigator?.createDialog(
"Pending payment",
"Payment is pending for approval. We will complete the transaction as soon as payment is approved."
)
}

BillingManagerWrapper.PurchaseState.INITIAL_PAYMENT_PENDING -> {
navigator?.createInitialDialog(
"Pending payment",
"Payment is pending for approval. We will complete the transaction as soon as payment is approved."
)
}

else -> {}
}
}

private fun handleError(error: Int) {
Expand Down Expand Up @@ -421,5 +437,9 @@ class SignUpViewModel @Inject constructor(
fun onAddFundsFinish()

fun onGoogleConnectFailure()

fun createDialog(title: String?, message: String?)

fun createInitialDialog(title: String?, message: String?)
}
}

0 comments on commit c392d73

Please sign in to comment.